FYP: show placeholder tiles when fetching membership or fyp itself.

This prevents the "no membership" and "no recommendations" message from flashing during load.
This commit is contained in:
infinite-persistence 2022-03-24 09:07:18 +08:00 committed by Thomas Zarebczan
parent 09557c8ce2
commit a96db41782
4 changed files with 39 additions and 8 deletions

View file

@ -33,7 +33,7 @@ declare type SearchState = {
hasReachedMaxResultsLength: {}, hasReachedMaxResultsLength: {},
searching: boolean, searching: boolean,
mentionQuery: string, mentionQuery: string,
personalRecommendations: { gid: string, uris: Array<string> }, personalRecommendations: { gid: string, uris: Array<string>, fetched: boolean },
}; };
declare type SearchSuccess = { declare type SearchSuccess = {
@ -44,7 +44,6 @@ declare type SearchSuccess = {
size: number, size: number,
uris: Array<string>, uris: Array<string>,
recsys: string, recsys: string,
query: string,
}, },
}; };

View file

@ -2,6 +2,7 @@
import React from 'react'; import React from 'react';
import Button from 'component/button'; import Button from 'component/button';
import ClaimList from 'component/claimList'; import ClaimList from 'component/claimList';
import ClaimPreviewTile from 'component/claimPreviewTile';
import I18nMessage from 'component/i18nMessage'; import I18nMessage from 'component/i18nMessage';
import * as ICONS from 'constants/icons'; import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages'; import * as PAGES from 'constants/pages';
@ -26,8 +27,8 @@ type Props = {
onLoad: (displayed: boolean) => void, onLoad: (displayed: boolean) => void,
// --- redux --- // --- redux ---
userId: ?string, userId: ?string,
personalRecommendations: { gid: string, uris: Array<string> }, personalRecommendations: { gid: string, uris: Array<string>, fetched: boolean },
hasMembership: boolean, hasMembership: ?boolean,
doFetchPersonalRecommendations: () => void, doFetchPersonalRecommendations: () => void,
}; };
@ -89,6 +90,26 @@ export default function RecommendedPersonal(props: Props) {
// ************************************************************************** // **************************************************************************
// ************************************************************************** // **************************************************************************
if (hasMembership === undefined || !personalRecommendations.fetched) {
return (
<>
{header}
<ul className="claim-grid">
{new Array(countCollapsed).fill(1).map((x, i) => (
<ClaimPreviewTile key={i} placeholder />
))}
</ul>
<div className="livestream-list--view-more" style={{ visibility: 'hidden' }}>
<Button
label='"View More" dummy to reduce layout shift'
button="link"
className="claim-grid__title--secondary"
/>
</div>
</>
);
}
if (!hasMembership) { if (!hasMembership) {
return ( return (
<div> <div>

View file

@ -22,7 +22,7 @@ const defaultState: SearchState = {
searching: false, searching: false,
results: [], results: [],
mentionQuery: '', mentionQuery: '',
personalRecommendations: { gid: '', uris: [] }, personalRecommendations: { gid: '', uris: [], fetched: false },
}; };
export default handleActions( export default handleActions(
@ -82,13 +82,17 @@ export default handleActions(
personalRecommendations: { personalRecommendations: {
gid: action.data.gid, gid: action.data.gid,
uris: action.data.uris, uris: action.data.uris,
fetched: true,
}, },
}; };
}, },
[ACTIONS.FYP_FETCH_FAILED]: (state: SearchState, action: any): SearchState => ({ [ACTIONS.FYP_FETCH_FAILED]: (state: SearchState, action: any): SearchState => ({
...state, ...state,
personalRecommendations: defaultState.personalRecommendations, personalRecommendations: {
...defaultState.personalRecommendations,
fetched: true,
},
}), }),
[ACTIONS.FYP_HIDE_URI]: (state: SearchState, action: any): SearchState => { [ACTIONS.FYP_HIDE_URI]: (state: SearchState, action: any): SearchState => {
@ -100,6 +104,7 @@ export default handleActions(
return { return {
...state, ...state,
personalRecommendations: { personalRecommendations: {
...state.personalRecommendations,
gid: state.personalRecommendations.gid, gid: state.personalRecommendations.gid,
uris, uris,
}, },

View file

@ -114,6 +114,12 @@ export const selectOdyseeMembershipIsPremiumPlus = (state) => {
return selectState(state).odyseeMembershipName === 'Premium+'; return selectState(state).odyseeMembershipName === 'Premium+';
}; };
/**
* selectHasOdyseeMembership
*
* @param state
* @returns 'undefined' if not yet fetched; boolean otherwise.
*/
export const selectHasOdyseeMembership = (state) => { export const selectHasOdyseeMembership = (state) => {
// @if process.env.NODE_ENV!='production' // @if process.env.NODE_ENV!='production'
const override = window.localStorage.getItem('hasMembershipOverride'); const override = window.localStorage.getItem('hasMembershipOverride');
@ -122,8 +128,8 @@ export const selectHasOdyseeMembership = (state) => {
} }
// @endif // @endif
const membershipName = selectOdyseeMembershipName(state); const membership = selectOdyseeMembershipName(state);
return Boolean(membershipName); return membership === undefined ? membership : Boolean(membership);
}; };
export const selectYouTubeImportVideosComplete = createSelector(selectState, (state) => { export const selectYouTubeImportVideosComplete = createSelector(selectState, (state) => {