0143b63c74
- Instead of 2 ways to display ads (DOM injection + React method) and having both of them clash, just do it the predictable React way. - Augment the existing React version to support tile layout + ability to place in last visible slot. - Consolidate styling code to scss ... DOM manipulations were making it even harder to maintain. - Removed the need to check for ad-blockers for now. It was being executed every time an ad is displayed, and now that we are displaying ads in more places, the gains doesn't justify the performance loss. Also, it wasn't being done for Recommended ads anyway, so the inconsistency probably means it's not needed in the first place. Other known issues fixed: - double ad injection when changing language via nag. - additional "total-blocking-time" due to ads at startup removed. - fixed ads not appearing in mobile homepage until navigated away and back to homepage. - enable ads in channel page. - support for both List and Tile layout.
220 lines
7 KiB
JavaScript
220 lines
7 KiB
JavaScript
// @flow
|
|
import { SHOW_ADS, DOMAIN, SIMPLE_SITE } from 'config';
|
|
import * as ICONS from 'constants/icons';
|
|
import * as PAGES from 'constants/pages';
|
|
import * as CS from 'constants/claim_search';
|
|
import React, { useRef } from 'react';
|
|
import Page from 'component/page';
|
|
import ClaimListDiscover from 'component/claimListDiscover';
|
|
import Button from 'component/button';
|
|
import useHover from 'effects/use-hover';
|
|
import { useIsMobile } from 'effects/use-screensize';
|
|
import analytics from 'analytics';
|
|
import HiddenNsfw from 'component/common/hidden-nsfw';
|
|
import Icon from 'component/common/icon';
|
|
import Ads from 'web/component/ads';
|
|
import LbcSymbol from 'component/common/lbc-symbol';
|
|
import I18nMessage from 'component/i18nMessage';
|
|
import moment from 'moment';
|
|
import LivestreamSection from './livestreamSection';
|
|
|
|
type Props = {
|
|
dynamicRouteProps: RowDataItem,
|
|
location: { search: string },
|
|
followedTags: Array<Tag>,
|
|
repostedUri: string,
|
|
repostedClaim: ?GenericClaim,
|
|
languageSetting: string,
|
|
searchInLanguage: boolean,
|
|
doToggleTagFollowDesktop: (string) => void,
|
|
doResolveUri: (string) => void,
|
|
isAuthenticated: boolean,
|
|
tileLayout: boolean,
|
|
activeLivestreams: ?LivestreamInfo,
|
|
doFetchActiveLivestreams: (orderBy: ?Array<string>, lang: ?Array<string>) => void,
|
|
};
|
|
|
|
function DiscoverPage(props: Props) {
|
|
const {
|
|
location: { search },
|
|
followedTags,
|
|
repostedClaim,
|
|
repostedUri,
|
|
languageSetting,
|
|
searchInLanguage,
|
|
doToggleTagFollowDesktop,
|
|
doResolveUri,
|
|
isAuthenticated,
|
|
tileLayout,
|
|
activeLivestreams,
|
|
doFetchActiveLivestreams,
|
|
dynamicRouteProps,
|
|
} = props;
|
|
|
|
const buttonRef = useRef();
|
|
const isHovering = useHover(buttonRef);
|
|
const isMobile = useIsMobile();
|
|
const isWildWest = window.location.pathname === `/$/${PAGES.WILD_WEST}`;
|
|
|
|
const urlParams = new URLSearchParams(search);
|
|
const langParam = urlParams.get(CS.LANGUAGE_KEY) || null;
|
|
const claimType = urlParams.get('claim_type');
|
|
const tagsQuery = urlParams.get('t') || null;
|
|
const tags = tagsQuery ? tagsQuery.split(',') : null;
|
|
const repostedClaimIsResolved = repostedUri && repostedClaim;
|
|
|
|
const discoverIcon = SIMPLE_SITE ? ICONS.WILD_WEST : ICONS.DISCOVER;
|
|
const discoverLabel = SIMPLE_SITE ? __('Wild West') : __('All Content');
|
|
// Eventually allow more than one tag on this page
|
|
// Restricting to one to make follow/unfollow simpler
|
|
const tag = (tags && tags[0]) || null;
|
|
const channelIds =
|
|
(dynamicRouteProps && dynamicRouteProps.options && dynamicRouteProps.options.channelIds) || undefined;
|
|
|
|
const isFollowing = followedTags.map(({ name }) => name).includes(tag);
|
|
let label = isFollowing ? __('Following --[button label indicating a channel has been followed]--') : __('Follow');
|
|
if (isHovering && isFollowing) {
|
|
label = __('Unfollow');
|
|
}
|
|
|
|
const includeLivestreams = !tagsQuery;
|
|
|
|
function getMeta() {
|
|
if (!dynamicRouteProps) {
|
|
return (
|
|
<a
|
|
className="help"
|
|
href="https://odysee.com/@OdyseeHelp:b/trending:50"
|
|
title={__('Learn more about Credits on %DOMAIN%', { DOMAIN })}
|
|
>
|
|
<I18nMessage tokens={{ lbc: <LbcSymbol /> }}>Results boosted by %lbc%</I18nMessage>
|
|
</a>
|
|
);
|
|
}
|
|
|
|
if (tag && !isMobile) {
|
|
return (
|
|
<Button
|
|
ref={buttonRef}
|
|
button="alt"
|
|
icon={ICONS.SUBSCRIBE}
|
|
iconColor="red"
|
|
onClick={handleFollowClick}
|
|
requiresAuth={IS_WEB}
|
|
label={label}
|
|
/>
|
|
);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getSubSection() {
|
|
if (includeLivestreams) {
|
|
return (
|
|
<LivestreamSection
|
|
tileLayout={repostedUri ? false : tileLayout}
|
|
channelIds={channelIds}
|
|
activeLivestreams={activeLivestreams}
|
|
doFetchActiveLivestreams={doFetchActiveLivestreams}
|
|
languageSetting={languageSetting}
|
|
searchInLanguage={searchInLanguage}
|
|
langParam={langParam}
|
|
/>
|
|
);
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function getPins(routeProps) {
|
|
if (routeProps && routeProps.pinnedUrls) {
|
|
return {
|
|
urls: routeProps.pinnedUrls,
|
|
onlyPinForOrder: CS.ORDER_BY_TRENDING,
|
|
};
|
|
}
|
|
}
|
|
|
|
React.useEffect(() => {
|
|
if (repostedUri && !repostedClaimIsResolved) {
|
|
doResolveUri(repostedUri);
|
|
}
|
|
}, [repostedUri, repostedClaimIsResolved, doResolveUri]);
|
|
|
|
function handleFollowClick() {
|
|
if (tag) {
|
|
doToggleTagFollowDesktop(tag);
|
|
|
|
const nowFollowing = !isFollowing;
|
|
analytics.tagFollowEvent(tag, nowFollowing, 'tag-page');
|
|
}
|
|
}
|
|
|
|
let headerLabel;
|
|
if (repostedClaim) {
|
|
headerLabel = __('Reposts of %uri%', { uri: repostedUri });
|
|
} else if (tag) {
|
|
headerLabel = (
|
|
<span>
|
|
<Icon icon={ICONS.TAG} size={10} />
|
|
{(tag === CS.TAGS_ALL && __('All Content')) || (tag === CS.TAGS_FOLLOWED && __('Followed Tags')) || tag}
|
|
|
|
<Button
|
|
className="claim-search__tags-link"
|
|
button="link"
|
|
label={__('Manage Tags')}
|
|
navigate={`/$/${PAGES.TAGS_FOLLOWING_MANAGE}`}
|
|
/>
|
|
</span>
|
|
);
|
|
} else {
|
|
headerLabel = (
|
|
<span>
|
|
<Icon icon={(dynamicRouteProps && dynamicRouteProps.icon) || discoverIcon} size={10} />
|
|
{(dynamicRouteProps && __(`${dynamicRouteProps.title}`)) || discoverLabel}
|
|
</span>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<Page noFooter fullWidthPage={tileLayout} className="main__discover">
|
|
<ClaimListDiscover
|
|
pins={getPins(dynamicRouteProps)}
|
|
hideFilters={SIMPLE_SITE ? !(dynamicRouteProps || tags) : undefined}
|
|
header={repostedUri ? <span /> : undefined}
|
|
subSection={getSubSection()}
|
|
tileLayout={repostedUri ? false : tileLayout}
|
|
defaultOrderBy={SIMPLE_SITE ? (dynamicRouteProps ? undefined : CS.ORDER_BY_TRENDING) : undefined}
|
|
claimType={claimType ? [claimType] : undefined}
|
|
headerLabel={headerLabel}
|
|
tags={tags}
|
|
hiddenNsfwMessage={<HiddenNsfw type="page" />}
|
|
repostedClaimId={repostedClaim ? repostedClaim.claim_id : null}
|
|
injectedItem={
|
|
SHOW_ADS && !isAuthenticated && !isWildWest && { node: <Ads small type="video" tileLayout={tileLayout} /> }
|
|
}
|
|
// Assume wild west page if no dynamicRouteProps
|
|
// Not a very good solution, but just doing it for now
|
|
// until we are sure this page will stay around
|
|
// TODO: find a better way to determine discover / wild west vs other modes release times
|
|
// for now including && !tags so that
|
|
releaseTime={
|
|
SIMPLE_SITE
|
|
? !dynamicRouteProps && !tags && `>${Math.floor(moment().subtract(1, 'day').startOf('week').unix())}`
|
|
: undefined
|
|
}
|
|
feeAmount={SIMPLE_SITE ? !dynamicRouteProps && CS.FEE_AMOUNT_ANY : undefined}
|
|
channelIds={channelIds}
|
|
limitClaimsPerChannel={
|
|
SIMPLE_SITE
|
|
? (dynamicRouteProps && dynamicRouteProps.options && dynamicRouteProps.options.limitClaimsPerChannel) || 3
|
|
: 3
|
|
}
|
|
meta={getMeta()}
|
|
hasSource
|
|
/>
|
|
</Page>
|
|
);
|
|
}
|
|
|
|
export default DiscoverPage;
|