Skip to content

Commit

Permalink
[front] feat: add a tab for "good short videos"
Browse files Browse the repository at this point in the history
Merge pull request #1825 from tournesol-app/good-short-videos-tab
  • Loading branch information
GresilleSiffle authored Nov 6, 2023
2 parents afa238f + 487c1b3 commit 1bae766
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 3 deletions.
2 changes: 2 additions & 0 deletions frontend/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
"recommendations": "Top of the month",
"yourScores": "Your scores",
"unconnected": "To connect",
"goodShortVideos": "Short videos",
"selectAVideo": "Select a video",
"select": "Select",
"youtubeVideoUnavailable": "YouTube video unavailable.",
Expand All @@ -122,6 +123,7 @@
"recommendations": "Videos recommended by the community appear here.",
"toConnect": "Videos isolated from your other comparisons appear here. Compare them to improve the recommendations.",
"rateLater": "Your rate-later videos appear here. You can add some to your list by clicking on the '+' sign on the video cards. You can also add them directly from <2>the extension</2>.",
"goodShortVideos": "A random sample of short videos recommended by the community.",
"errorOnLoading": "An error occurred while loading the results.",
"emptyList": "This list is empty."
},
Expand Down
2 changes: 2 additions & 0 deletions frontend/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@
"recommendations": "Top du mois",
"yourScores": "Vos scores",
"unconnected": "À relier",
"goodShortVideos": "Vidéos courtes",
"selectAVideo": "Sélectionner une vidéo",
"select": "Sélectionner",
"youtubeVideoUnavailable": "Vidéo YouTube indisponible.",
Expand All @@ -126,6 +127,7 @@
"recommendations": "Les vidéos recommandées par la communauté apparaissent ici.",
"toConnect": "Les vidéos isolées du reste de vos comparaisons apparaissent ici. Comparez-les pour améliorer les recommandations.",
"rateLater": "Vos vidéos à comparer plus tard apparaissent ici. Vous pouvez en ajouter sur le site web via le bouton '+'. Vous pouvez aussi les ajouter directement depuis YouTube grâce à <2>l'extension</2>.",
"goodShortVideos": "Un échantillon aléatoire de vidéos courtes recommandées par la communauté.",
"errorOnLoading": "Une erreur est survenue lors du chargement des résultats.",
"emptyList": "Cette liste est vide."
},
Expand Down
15 changes: 13 additions & 2 deletions frontend/src/features/entity_selector/EntitySelectButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import {
} from 'src/utils/constants';
import { UsersService } from 'src/services/openapi';
import { getRecommendations } from 'src/utils/api/recommendations';
import { getGoodShortVideos } from 'src/utils/api/goodShortVideos';
import { getAllCandidates } from 'src/utils/polls/presidentielle2022';
import SelectorListBox, { EntitiesTab } from './EntityTabsBox';
import SelectorPopper from './SelectorPopper';
import { useLoginState } from 'src/hooks';
import { useLoginState, usePreferredLanguages } from 'src/hooks';
import { ComparisonsCountContext } from 'src/pages/comparisons/Comparison';
import { EntityObject } from 'src/utils/types';

Expand Down Expand Up @@ -55,6 +56,8 @@ const VideoInput = ({

const comparisonsCount = useContext(ComparisonsCountContext).comparisonsCount;

const preferredLanguages = usePreferredLanguages({ pollName });

const handleOptionClick = (uid: string) => {
onChange(uid);
setSuggestionsOpen(false);
Expand Down Expand Up @@ -157,8 +160,16 @@ const VideoInput = ({
},
disabled: !isLoggedIn || !otherUid,
},
{
name: 'good-short-videos',
label: t('entitySelector.goodShortVideos'),
fetch: async () => {
return await getGoodShortVideos({ preferredLanguages });
},
disabled: !isLoggedIn,
},
],
[t, isLoggedIn, otherUid, pollName]
[t, isLoggedIn, otherUid, pollName, preferredLanguages]
);

return (
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/features/entity_selector/EntityTabsBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const TabInfo = ({
.
</Trans>
),
'good-short-videos': t('tabsBox.goodShortVideos'),
};

if (!(messageKey in descriptionMessages)) {
Expand All @@ -105,7 +106,7 @@ const TabInfo = ({
const EntityTabsBox = ({
tabs,
onSelectEntity,
width = 'min(700px, 100vw)',
width = 'min(760px, 100vw)',
elevation = 1,
maxHeight = '40vh',
withLink = false,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export { useNotifications } from './useNotifications';
export { useRefreshSettings } from './useRefreshSettings';
export { useScrollToLocation } from './useScrollToLocation';
export { useStats } from './useStats';
export { usePreferredLanguages } from './usePreferredLanguages';
15 changes: 15 additions & 0 deletions frontend/src/hooks/usePreferredLanguages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useSelector } from 'react-redux';
import { selectSettings } from 'src/features/settings/userSettingsSlice';
import { PollUserSettingsKeys } from 'src/utils/types';
import { recommendationsLanguagesFromNavigator } from 'src/utils/recommendationsLanguages';

export const usePreferredLanguages = ({ pollName }: { pollName: string }) => {
const userSettings = useSelector(selectSettings).settings;
let preferredLanguages =
userSettings?.[pollName as PollUserSettingsKeys]
?.recommendations__default_languages;

preferredLanguages ??= recommendationsLanguagesFromNavigator().split(',');

return preferredLanguages;
};
38 changes: 38 additions & 0 deletions frontend/src/utils/api/goodShortVideos.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { PollsService } from 'src/services/openapi';
import { Recommendation } from 'src/services/openapi';

const shuffleRecommendations = (array: Recommendation[]) => {
// https://stackoverflow.com/a/12646864/188760
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
};

export const getGoodShortVideos = async ({
preferredLanguages,
}: {
preferredLanguages: string[];
}): Promise<Recommendation[]> => {
const metadata: Record<string, string | string[]> = {};

const minutesMax = 5;
const top = 100;

metadata['duration:lte:int'] = (60 * minutesMax).toString();
metadata['language'] = preferredLanguages;

const videos = await PollsService.pollsRecommendationsList({
name: 'videos',
metadata: metadata,
limit: top,
excludeComparedEntities: true,
}).then((data) => data.results ?? []);

const returnCount = 20;

shuffleRecommendations(videos);
videos.splice(returnCount);

return videos;
};

0 comments on commit 1bae766

Please sign in to comment.