Add outbrain
- Only add for unauthenticated users for now. We can change that to look at premium later without having to touch `app/view.jsx`. - Only show the ad after knowing the ad is filled; this prevents the invisible container from blocking stuff while waiting, or even worse, when not filled.
This commit is contained in:
parent
d2fdcc970f
commit
802b5d5a18
4 changed files with 80 additions and 2 deletions
|
@ -2,7 +2,7 @@ import { hot } from 'react-hot-loader/root';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { selectGetSyncErrorMessage, selectSyncFatalError, selectSyncIsLocked } from 'redux/selectors/sync';
|
import { selectGetSyncErrorMessage, selectSyncFatalError, selectSyncIsLocked } from 'redux/selectors/sync';
|
||||||
import { doUserSetReferrer } from 'redux/actions/user';
|
import { doUserSetReferrer } from 'redux/actions/user';
|
||||||
import { selectUser, selectUserLocale, selectUserVerifiedEmail } from 'redux/selectors/user';
|
import { selectOdyseeMembershipIsPremiumPlus, selectUser, selectUserLocale, selectUserVerifiedEmail } from 'redux/selectors/user';
|
||||||
import { selectUnclaimedRewards } from 'redux/selectors/rewards';
|
import { selectUnclaimedRewards } from 'redux/selectors/rewards';
|
||||||
import { doFetchChannelListMine, doFetchCollectionListMine, doResolveUris } from 'redux/actions/claims';
|
import { doFetchChannelListMine, doFetchCollectionListMine, doResolveUris } from 'redux/actions/claims';
|
||||||
import { selectMyChannelClaimIds } from 'redux/selectors/claims';
|
import { selectMyChannelClaimIds } from 'redux/selectors/claims';
|
||||||
|
@ -41,6 +41,7 @@ const select = (state) => ({
|
||||||
activeChannelClaim: selectActiveChannelClaim(state),
|
activeChannelClaim: selectActiveChannelClaim(state),
|
||||||
myChannelClaimIds: selectMyChannelClaimIds(state),
|
myChannelClaimIds: selectMyChannelClaimIds(state),
|
||||||
subscriptions: selectSubscriptions(state),
|
subscriptions: selectSubscriptions(state),
|
||||||
|
hasPremiumPlus: selectOdyseeMembershipIsPremiumPlus(state),
|
||||||
});
|
});
|
||||||
|
|
||||||
const perform = (dispatch) => ({
|
const perform = (dispatch) => ({
|
||||||
|
|
|
@ -16,6 +16,7 @@ import useKonamiListener from 'util/enhanced-layout';
|
||||||
import Yrbl from 'component/yrbl';
|
import Yrbl from 'component/yrbl';
|
||||||
import FileRenderFloating from 'component/fileRenderFloating';
|
import FileRenderFloating from 'component/fileRenderFloating';
|
||||||
import { withRouter } from 'react-router';
|
import { withRouter } from 'react-router';
|
||||||
|
import useAdOutbrain from 'effects/use-ad-outbrain';
|
||||||
import usePrevious from 'effects/use-previous';
|
import usePrevious from 'effects/use-previous';
|
||||||
import Nag from 'component/common/nag';
|
import Nag from 'component/common/nag';
|
||||||
import REWARDS from 'rewards';
|
import REWARDS from 'rewards';
|
||||||
|
@ -86,6 +87,7 @@ type Props = {
|
||||||
activeChannelClaim: ?ChannelClaim,
|
activeChannelClaim: ?ChannelClaim,
|
||||||
myChannelClaimIds: ?Array<string>,
|
myChannelClaimIds: ?Array<string>,
|
||||||
subscriptions: Array<Subscription>,
|
subscriptions: Array<Subscription>,
|
||||||
|
hasPremiumPlus: ?boolean,
|
||||||
setActiveChannelIfNotSet: () => void,
|
setActiveChannelIfNotSet: () => void,
|
||||||
setIncognito: (boolean) => void,
|
setIncognito: (boolean) => void,
|
||||||
fetchModBlockedList: () => void,
|
fetchModBlockedList: () => void,
|
||||||
|
@ -125,6 +127,7 @@ function App(props: Props) {
|
||||||
fetchModBlockedList,
|
fetchModBlockedList,
|
||||||
resolveUris,
|
resolveUris,
|
||||||
subscriptions,
|
subscriptions,
|
||||||
|
hasPremiumPlus,
|
||||||
fetchModAmIList,
|
fetchModAmIList,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
@ -480,6 +483,8 @@ function App(props: Props) {
|
||||||
|
|
||||||
useDegradedPerformance(setLbryTvApiStatus, user);
|
useDegradedPerformance(setLbryTvApiStatus, user);
|
||||||
|
|
||||||
|
useAdOutbrain(Boolean(hasPremiumPlus), isAuthenticated);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// When language is changed or translations are fetched, we render.
|
// When language is changed or translations are fetched, we render.
|
||||||
setLangRenderKey(Date.now());
|
setLangRenderKey(Date.now());
|
||||||
|
|
62
ui/effects/use-ad-outbrain.js
Normal file
62
ui/effects/use-ad-outbrain.js
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
// @flow
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function inIFrame() {
|
||||||
|
try {
|
||||||
|
return window.self !== window.top;
|
||||||
|
} catch (e) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const LOAD_AD_DELAY_MS = 3000; // Wait past boot-up and core-vitals period.
|
||||||
|
const OUTBRAIN_CONTAINER_KEY = 'outbrainStickyParent';
|
||||||
|
|
||||||
|
let script;
|
||||||
|
|
||||||
|
export default function useAdOutbrain(hasPremiumPlus: boolean, isAuthenticated: boolean) {
|
||||||
|
// Only look at authentication for now. Eventually, we'll only use 'hasPremiumPlus'.
|
||||||
|
const isAuthenticatedRef = React.useRef(isAuthenticated);
|
||||||
|
isAuthenticatedRef.current = isAuthenticated;
|
||||||
|
|
||||||
|
function loadListener() {
|
||||||
|
const container = window[OUTBRAIN_CONTAINER_KEY];
|
||||||
|
if (container) {
|
||||||
|
// Hide it immediately while we wait for ads to be filled. This prevents
|
||||||
|
// the invisible container from blocking our content.
|
||||||
|
container.style.visibility = 'hidden';
|
||||||
|
|
||||||
|
// Restore visibility after confirming the ad is filled. If it is filled
|
||||||
|
// after the stipulated time, well, no soup for you.
|
||||||
|
setTimeout(() => {
|
||||||
|
const filledAd = document.querySelector('.ob-widget-items-container');
|
||||||
|
if (filledAd && !isAuthenticatedRef.current) {
|
||||||
|
container.style.visibility = 'visible';
|
||||||
|
}
|
||||||
|
}, 5000); // 3s is sufficient for Chrome, but Firefox seems to take ~5s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!inIFrame() && !isAuthenticated && !script) {
|
||||||
|
const loadTimer = setTimeout(() => {
|
||||||
|
script = document.createElement('script');
|
||||||
|
script.src = 'https://adncdnend.azureedge.net/adtags/odysee.adn.js';
|
||||||
|
script.async = true;
|
||||||
|
script.addEventListener('load', loadListener); // not using 'script.onload'; seem unreliable with async.
|
||||||
|
|
||||||
|
// $FlowFixMe
|
||||||
|
document.body.appendChild(script);
|
||||||
|
}, LOAD_AD_DELAY_MS);
|
||||||
|
|
||||||
|
return () => clearTimeout(loadTimer);
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps, (on mount only)
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (isAuthenticated && window[OUTBRAIN_CONTAINER_KEY]) {
|
||||||
|
window[OUTBRAIN_CONTAINER_KEY].style.display = 'none';
|
||||||
|
}
|
||||||
|
}, [isAuthenticated]);
|
||||||
|
}
|
|
@ -54,7 +54,7 @@
|
||||||
width: $width;
|
width: $width;
|
||||||
}
|
}
|
||||||
|
|
||||||
div[style*='transform-origin: left bottom;'] {
|
div[style*='transform-origin: left bottom'] {
|
||||||
// [Floating ad]
|
// [Floating ad]
|
||||||
// Hide for now since can't get it to work in a consistent manner between:
|
// Hide for now since can't get it to work in a consistent manner between:
|
||||||
// - EU and non-EU version
|
// - EU and non-EU version
|
||||||
|
@ -187,3 +187,13 @@
|
||||||
.exp-ui__logo {
|
.exp-ui__logo {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ****************************************************************************
|
||||||
|
// Outbrain
|
||||||
|
// ****************************************************************************
|
||||||
|
|
||||||
|
.ob-widget-items-container {
|
||||||
|
padding-left: var(--spacing-xs);
|
||||||
|
padding-right: var(--spacing-xs);
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue