Re-implement/enable sticky ad
## Ticket
1583: "add incontent ads to category/channel pages (break up every X claims?), or add back bottom ad in those areas."
## Behavioral changes
- Hide when in homepage (as currently we have ads between categories).
- Fix the light theme (it was transparent).
## Code changes
- While an Effect is the 'right' choice given that there is no jsx to mount, the need to prop-drill from the parent was getting a bit annoying, so converted to a Component instead.
- Remove the delay for Core Vitals avoidance for now -- seems to make the sticky less likely to serve an ad.
- Now that the membership state is correctly populated for incognito (see 9d830615
), there is no more need to check for `isAuthenticated`.
This commit is contained in:
parent
4ea6b848d1
commit
0bcea943d5
5 changed files with 105 additions and 65 deletions
|
@ -21,6 +21,7 @@ import usePersistedState from 'effects/use-persisted-state';
|
|||
import useConnectionStatus from 'effects/use-connection-status';
|
||||
import Spinner from 'component/spinner';
|
||||
import LANGUAGES from 'constants/languages';
|
||||
import AdsSticky from 'web/component/adsSticky';
|
||||
import YoutubeWelcome from 'web/component/youtubeReferralWelcome';
|
||||
import {
|
||||
useDegradedPerformance,
|
||||
|
@ -558,6 +559,8 @@ function App(props: Props) {
|
|||
)}
|
||||
{getStatusNag()}
|
||||
</React.Suspense>
|
||||
|
||||
<AdsSticky />
|
||||
</React.Fragment>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
@ -1,65 +0,0 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import * as PAGES from 'constants/pages';
|
||||
|
||||
function inIFrame() {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const EXCLUDED_PATHS = Object.freeze([`/$/${PAGES.AUTH}`, `/$/${PAGES.AUTH_SIGNIN}`, `/$/${PAGES.AUTH_VERIFY}`]);
|
||||
|
||||
const LOAD_AD_DELAY_MS = 3000; // Wait past boot-up and core-vitals period.
|
||||
const OUTBRAIN_CONTAINER_KEY = 'outbrainSizeDiv';
|
||||
let script;
|
||||
|
||||
/**
|
||||
* @param hasPremiumPlus `undefined` if not yet fetched, boolean otherwise.
|
||||
* @param isAuthenticated `undefined` if email is not fetched, boolean
|
||||
* otherwise.
|
||||
* @param pathname Reminder: the component using this effect must be listening
|
||||
* to path changes (e.g. useHistory, etc.). This value must not
|
||||
* come from window.location.pathname, which doesn't spark an
|
||||
* update.
|
||||
*/
|
||||
export default function useAdOutbrain(hasPremiumPlus: ?boolean, isAuthenticated: ?boolean, pathname: string) {
|
||||
// Still need to look at `isAuthenticated` because `hasPremiumPlus` remains
|
||||
// in unfetched (`undefined) state in Incognito.
|
||||
const loadScript = isAuthenticated === false || hasPremiumPlus === false;
|
||||
|
||||
const propRef = React.useRef({ hasPremiumPlus, pathname });
|
||||
propRef.current = { hasPremiumPlus, pathname };
|
||||
|
||||
function resolveVisibility() {
|
||||
if (window[OUTBRAIN_CONTAINER_KEY]) {
|
||||
if (propRef.current.hasPremiumPlus) {
|
||||
window[OUTBRAIN_CONTAINER_KEY].style.display = 'none';
|
||||
} else {
|
||||
window[OUTBRAIN_CONTAINER_KEY].style.display = EXCLUDED_PATHS.includes(propRef.current.pathname) ? 'none' : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!inIFrame() && loadScript && !script) {
|
||||
const loadTimer = setTimeout(() => {
|
||||
script = document.createElement('script');
|
||||
script.src = 'https://adncdnend.azureedge.net/adtags/odysee.adn.js';
|
||||
script.async = true;
|
||||
script.addEventListener('load', resolveVisibility);
|
||||
|
||||
// $FlowFixMe
|
||||
document.body.appendChild(script);
|
||||
}, LOAD_AD_DELAY_MS);
|
||||
|
||||
return () => clearTimeout(loadTimer);
|
||||
}
|
||||
}, [loadScript]);
|
||||
|
||||
React.useEffect(() => {
|
||||
resolveVisibility();
|
||||
}, [hasPremiumPlus, pathname]);
|
||||
}
|
|
@ -323,6 +323,8 @@
|
|||
.ob-widget .ob-unit.ob-rec-text {
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
background-color: var(--color-ads-background);
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
|
|
20
web/component/adsSticky/index.js
Normal file
20
web/component/adsSticky/index.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import { connect } from 'react-redux';
|
||||
import * as SETTINGS from 'constants/settings';
|
||||
import { doSetAdBlockerFound } from 'redux/actions/app';
|
||||
import { selectAdBlockerFound } from 'redux/selectors/app';
|
||||
import { selectClientSetting } from 'redux/selectors/settings';
|
||||
import { selectOdyseeMembershipIsPremiumPlus, selectUserCountry } from 'redux/selectors/user';
|
||||
import AdsSticky from './view';
|
||||
|
||||
const select = (state, props) => ({
|
||||
isAdBlockerFound: selectAdBlockerFound(state),
|
||||
userHasPremiumPlus: selectOdyseeMembershipIsPremiumPlus(state),
|
||||
userCountry: selectUserCountry(state),
|
||||
currentTheme: selectClientSetting(state, SETTINGS.THEME),
|
||||
});
|
||||
|
||||
const perform = {
|
||||
doSetAdBlockerFound,
|
||||
};
|
||||
|
||||
export default connect(select, perform)(AdsSticky);
|
80
web/component/adsSticky/view.jsx
Normal file
80
web/component/adsSticky/view.jsx
Normal file
|
@ -0,0 +1,80 @@
|
|||
// @flow
|
||||
import React from 'react';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
import * as PAGES from 'constants/pages';
|
||||
import useShouldShowAds from 'effects/use-should-show-ads';
|
||||
|
||||
// ****************************************************************************
|
||||
// AdsSticky
|
||||
// ****************************************************************************
|
||||
|
||||
const PATH_BLACKLIST = [
|
||||
// Don't show sticky in these paths:
|
||||
{ path: `/`, exact: true },
|
||||
{ path: `/$/${PAGES.AUTH}`, exact: false },
|
||||
{ path: `/$/${PAGES.AUTH_SIGNIN}`, exact: false },
|
||||
{ path: `/$/${PAGES.AUTH_VERIFY}`, exact: false },
|
||||
{ path: `/$/${PAGES.SETTINGS}`, exact: false },
|
||||
];
|
||||
|
||||
const OUTBRAIN_CONTAINER_KEY = 'outbrainSizeDiv';
|
||||
let gScript;
|
||||
|
||||
type Props = {
|
||||
isAdBlockerFound: ?boolean,
|
||||
userHasPremiumPlus: boolean,
|
||||
userCountry: string,
|
||||
currentTheme: string,
|
||||
doSetAdBlockerFound: (boolean) => void,
|
||||
};
|
||||
|
||||
export default function AdsSticky(props: Props) {
|
||||
const { isAdBlockerFound, userHasPremiumPlus, userCountry, doSetAdBlockerFound } = props;
|
||||
const shouldShowAds = useShouldShowAds(userHasPremiumPlus, userCountry, isAdBlockerFound, doSetAdBlockerFound);
|
||||
const {
|
||||
location: { pathname },
|
||||
} = useHistory();
|
||||
|
||||
// -- Mount script; 1 per session.
|
||||
React.useEffect(() => {
|
||||
if (shouldShowAds && !gScript && !inIFrame()) {
|
||||
gScript = document.createElement('script');
|
||||
gScript.src = 'https://adncdnend.azureedge.net/adtags/odysee.adn.js';
|
||||
gScript.async = true;
|
||||
|
||||
// $FlowFixMe
|
||||
document.body.appendChild(gScript);
|
||||
}
|
||||
}, [shouldShowAds]);
|
||||
|
||||
// -- Update visibility per pathname
|
||||
React.useEffect(() => {
|
||||
const container = window[OUTBRAIN_CONTAINER_KEY];
|
||||
if (container) {
|
||||
for (const x of PATH_BLACKLIST) {
|
||||
const found = (x.exact && pathname === x.path) || (!x.exact && pathname.startsWith(x.path));
|
||||
if (found) {
|
||||
container.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
container.style.display = '';
|
||||
}
|
||||
}, [pathname]);
|
||||
|
||||
// Nothing for us to mount; the ad script will handle everything.
|
||||
return null;
|
||||
}
|
||||
|
||||
// ****************************************************************************
|
||||
// Helpers
|
||||
// ****************************************************************************
|
||||
|
||||
function inIFrame() {
|
||||
try {
|
||||
return window.self !== window.top;
|
||||
} catch (e) {
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue