lbry-desktop/ui/component/recommendedPersonal/view.jsx
infinite-persistence bffc27e8d0
Just always show homepage segment titles.. (#1116)
## Issue
- "Following" was showing up in place of "Featured"
- "Following" doesn't appear until livestreams are fetched, causing shifts.

When "Upcoming Livestreams" was implemented, it was trying to retain the original behavior of not showing "Following" title if that was the first in the list.

Not only is it a chicken-and-egg problem, but it causes extra renders due to the need to check if the other guys was rendered.

With FYP, there are now more combinations to handle.

## Change
Just show the title...
2022-03-16 08:49:44 -04:00

147 lines
4.9 KiB
JavaScript

// @flow
import React from 'react';
import Button from 'component/button';
import HelpLink from 'component/common/help-link';
import Icon from 'component/common/icon';
import ClaimList from 'component/claimList';
import { URL, SHARE_DOMAIN_URL } from 'config';
import * as ICONS from 'constants/icons';
import * as PAGES from 'constants/pages';
import { useIsLargeScreen, useIsMediumScreen } from 'effects/use-screensize';
// TODO: recsysFyp will be moved into 'RecSys', so the redux import in a jsx
// violation is just temporary.
import { recsysFyp } from 'redux/actions/search';
// ****************************************************************************
// SectionHeader (TODO: DRY)
// ****************************************************************************
type SectionHeaderProps = {
title: string,
navigate?: string,
icon?: string,
help?: string,
};
const SectionHeader = ({ title, icon = '', help }: SectionHeaderProps) => {
const SHARE_DOMAIN = SHARE_DOMAIN_URL || URL;
return (
<h1 className="claim-grid__header">
<Icon className="claim-grid__header-icon" sectionIcon icon={icon} size={20} />
<span className="claim-grid__title">{title}</span>
{help}
<HelpLink href={`${SHARE_DOMAIN}/$/${PAGES.FYP}`} iconSize={24} description={__('Learn more')} />
</h1>
);
};
// ****************************************************************************
// RecommendedPersonal
// ****************************************************************************
const VIEW = { ALL_VISIBLE: 0, COLLAPSED: 1, EXPANDED: 2 };
function getSuitablePageSizeForScreen(defaultSize, isLargeScreen, isMediumScreen) {
return isMediumScreen ? 6 : isLargeScreen ? Math.ceil(defaultSize * (3 / 2)) : defaultSize;
}
type Props = {
onLoad: (displayed: boolean) => void,
// --- redux ---
userId: ?string,
personalRecommendations: { gid: string, uris: Array<string> },
hasMembership: boolean,
doFetchPersonalRecommendations: () => void,
};
export default function RecommendedPersonal(props: Props) {
const { onLoad, userId, personalRecommendations, hasMembership, doFetchPersonalRecommendations } = props;
const [markedGid, setMarkedGid] = React.useState('');
const [view, setView] = React.useState(VIEW.ALL_VISIBLE);
const isLargeScreen = useIsLargeScreen();
const isMediumScreen = useIsMediumScreen();
const count = personalRecommendations.uris.length;
const countCollapsed = getSuitablePageSizeForScreen(8, isLargeScreen, isMediumScreen);
const finalCount = view === VIEW.ALL_VISIBLE ? count : view === VIEW.COLLAPSED ? countCollapsed : count;
// **************************************************************************
// Effects
// **************************************************************************
React.useEffect(() => {
// -- Update parent's callback request
if (typeof onLoad === 'function') {
onLoad(count > 0);
}
}, [count, onLoad]);
React.useEffect(() => {
// -- Resolve the view state:
let newView;
if (count <= countCollapsed) {
newView = VIEW.ALL_VISIBLE;
} else {
if (view === VIEW.ALL_VISIBLE) {
newView = VIEW.COLLAPSED;
}
}
if (newView && newView !== view) {
setView(newView);
}
}, [count, countCollapsed, view, setView]);
React.useEffect(() => {
// -- Mark recommendations when rendered:
if (userId && markedGid !== personalRecommendations.gid) {
setMarkedGid(personalRecommendations.gid);
recsysFyp.markPersonalRecommendations(userId, personalRecommendations.gid);
}
}, [userId, markedGid, personalRecommendations.gid]);
React.useEffect(() => {
// -- Fetch FYP
if (hasMembership || process.env.ENABLE_WIP_FEATURES) {
doFetchPersonalRecommendations();
}
}, [hasMembership, doFetchPersonalRecommendations]);
// **************************************************************************
// **************************************************************************
if ((!hasMembership && !process.env.ENABLE_WIP_FEATURES) || count < 1) {
return null;
}
return (
<>
<SectionHeader title={__('Recommended For You')} icon={ICONS.WEB} />
<ClaimList
tileLayout
uris={personalRecommendations.uris.slice(0, finalCount)}
fypId={personalRecommendations.gid}
/>
{view !== VIEW.ALL_VISIBLE && (
<div className="livestream-list--view-more">
<Button
label={view === VIEW.COLLAPSED ? __('Show more') : __('Show less')}
button="link"
iconRight={view === VIEW.COLLAPSED ? ICONS.DOWN : ICONS.UP}
className="claim-grid__title--secondary"
onClick={() => {
if (view === VIEW.COLLAPSED) {
setView(VIEW.EXPANDED);
} else {
setView(VIEW.COLLAPSED);
window.scrollTo({ top: 0, behavior: 'smooth' });
}
}}
/>
</div>
)}
</>
);
}