Adds GDPR support (#311)
* add gdpr support * only run on production * testing implementation * just needs last touches then ready * ready for merge * add cookies to sidebar * hide button when secureprivacy not available * switch over to loading script as a react hook * conditionally add secureprivacy script * save gdpr status on session * better design
This commit is contained in:
parent
3c4ccdd2fe
commit
f2715fa97b
5 changed files with 92 additions and 26 deletions
|
@ -47,6 +47,7 @@ export const MAIN_WRAPPER_CLASS = 'main-wrapper';
|
||||||
export const IS_MAC = navigator.userAgent.indexOf('Mac OS X') !== -1;
|
export const IS_MAC = navigator.userAgent.indexOf('Mac OS X') !== -1;
|
||||||
|
|
||||||
const imaLibraryPath = 'https://imasdk.googleapis.com/js/sdkloader/ima3.js';
|
const imaLibraryPath = 'https://imasdk.googleapis.com/js/sdkloader/ima3.js';
|
||||||
|
const securePrivacyScriptUrl = 'https://app.secureprivacy.ai/script/6194129b66262906dd4a5f43.js';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
language: string,
|
language: string,
|
||||||
|
@ -327,6 +328,46 @@ function App(props: Props) {
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// add secure privacy script
|
||||||
|
useEffect(() => {
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = securePrivacyScriptUrl;
|
||||||
|
script.async = true;
|
||||||
|
// might use this for future checking to prevent doubleloading
|
||||||
|
script.id = 'securePrivacy';
|
||||||
|
|
||||||
|
const getLocaleEndpoint = 'https://api.odysee.com/locale/get';
|
||||||
|
const gdprRequired = localStorage.getItem('gdprRequired');
|
||||||
|
// gdpr is known to be required, add script
|
||||||
|
if (gdprRequired === 'true') {
|
||||||
|
// $FlowFixMe
|
||||||
|
document.head.appendChild(script);
|
||||||
|
}
|
||||||
|
|
||||||
|
// haven't done a gdpr check, do it now
|
||||||
|
if (gdprRequired === null) {
|
||||||
|
(async function() {
|
||||||
|
const response = await fetch(getLocaleEndpoint);
|
||||||
|
const json = await response.json();
|
||||||
|
const gdprRequiredBasedOnLocation = json.data.gdpr_required;
|
||||||
|
// note we need gdpr and load script
|
||||||
|
if (gdprRequiredBasedOnLocation) {
|
||||||
|
localStorage.setItem('gdprRequired', 'true');
|
||||||
|
// $FlowFixMe
|
||||||
|
document.head.appendChild(script);
|
||||||
|
// note we don't need gdpr, save to session
|
||||||
|
} else if (gdprRequiredBasedOnLocation === false) {
|
||||||
|
localStorage.setItem('gdprRequired', 'false');
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
// $FlowFixMe
|
||||||
|
document.head.removeChild(script);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
// ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too.
|
// ready for sync syncs, however after signin when hasVerifiedEmail, that syncs too.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// signInSyncPref is cleared after sharedState loop.
|
// signInSyncPref is cleared after sharedState loop.
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { Node } from 'react';
|
||||||
import * as PAGES from 'constants/pages';
|
import * as PAGES from 'constants/pages';
|
||||||
import * as ICONS from 'constants/icons';
|
import * as ICONS from 'constants/icons';
|
||||||
import * as KEYCODES from 'constants/keycodes';
|
import * as KEYCODES from 'constants/keycodes';
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import Icon from 'component/common/icon';
|
import Icon from 'component/common/icon';
|
||||||
|
@ -323,6 +323,15 @@ function SideNavigation(props: Props) {
|
||||||
return () => window.removeEventListener('keydown', handleKeydown);
|
return () => window.removeEventListener('keydown', handleKeydown);
|
||||||
}, [sidebarOpen, setSidebarOpen, isAbsolute]);
|
}, [sidebarOpen, setSidebarOpen, isAbsolute]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!window.sp) {
|
||||||
|
const gdprDiv = document.getElementById('gdprPrivacyFooter');
|
||||||
|
if (gdprDiv) {
|
||||||
|
gdprDiv.style.display = 'none';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [sidebarOpen]);
|
||||||
|
|
||||||
const unAuthNudge =
|
const unAuthNudge =
|
||||||
DOMAIN === 'lbry.tv' ? null : (
|
DOMAIN === 'lbry.tv' ? null : (
|
||||||
<div className="navigation__auth-nudge">
|
<div className="navigation__auth-nudge">
|
||||||
|
@ -354,6 +363,9 @@ function SideNavigation(props: Props) {
|
||||||
<li className="navigation-link">
|
<li className="navigation-link">
|
||||||
<Button label={__('Privacy Policy')} href="https://odysee.com/$/privacypolicy" />
|
<Button label={__('Privacy Policy')} href="https://odysee.com/$/privacypolicy" />
|
||||||
</li>
|
</li>
|
||||||
|
<li className="navigation-link" id="gdprPrivacyFooter">
|
||||||
|
<Button label={__('Cookies')} onClick={() => window.sp && window.sp.showPrivacyBanner()} />
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -73,6 +73,7 @@ const videoPlaybackRates = [0.25, 0.5, 0.75, 1, 1.1, 1.25, 1.5, 1.75, 2];
|
||||||
|
|
||||||
const IS_IOS =
|
const IS_IOS =
|
||||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||||
|
// for iOS 13+ , platform is MacIntel, so use this to test
|
||||||
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
|
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
|
||||||
!window.MSStream;
|
!window.MSStream;
|
||||||
|
|
||||||
|
|
|
@ -8,10 +8,20 @@ import Button from 'component/button';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
|
|
||||||
const ADS_URL =
|
|
||||||
'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Responsive_Floating_DFP_Rev70_1011.js';
|
|
||||||
const IS_MOBILE = typeof window.orientation !== 'undefined';
|
const IS_MOBILE = typeof window.orientation !== 'undefined';
|
||||||
|
|
||||||
|
const ADS_URL = 'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Responsive_Floating_DFP_Rev70_1011.js';
|
||||||
|
const ADS_TAG = 'vidcrunchJS537102317';
|
||||||
|
|
||||||
|
const IOS_ADS_URL = 'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Mobile_Floating_DFP_Rev70_1611.js';
|
||||||
|
const IOS_ADS_TAG = 'vidcrunchJS199212779';
|
||||||
|
|
||||||
|
const IS_IOS =
|
||||||
|
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||||
|
// for iOS 13+ , platform is MacIntel, so use this to test
|
||||||
|
(navigator.platform === 'MacIntel' && navigator.maxTouchPoints > 1)) &&
|
||||||
|
!window.MSStream;
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
location: { pathname: string },
|
location: { pathname: string },
|
||||||
type: string,
|
type: string,
|
||||||
|
@ -27,18 +37,23 @@ function Ads(props: Props) {
|
||||||
small,
|
small,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
let scriptUrlToUse;
|
||||||
|
let tagNameToUse;
|
||||||
|
if (IS_IOS) {
|
||||||
|
tagNameToUse = IOS_ADS_TAG;
|
||||||
|
scriptUrlToUse = IOS_ADS_URL;
|
||||||
|
} else {
|
||||||
|
tagNameToUse = ADS_TAG;
|
||||||
|
scriptUrlToUse = ADS_URL;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (SHOW_ADS && type === 'video') {
|
if (SHOW_ADS && type === 'video') {
|
||||||
let script;
|
let script;
|
||||||
try {
|
try {
|
||||||
const d = document;
|
let fjs = document.getElementsByTagName('script')[0];
|
||||||
const s = 'script';
|
script = document.createElement('script');
|
||||||
const n = 'vidcrunch';
|
script.src = scriptUrlToUse;
|
||||||
let fjs = d.getElementsByTagName(s)[0];
|
|
||||||
script = d.createElement(s);
|
|
||||||
script.className = n;
|
|
||||||
script.src =
|
|
||||||
'https://cdn.vidcrunch.com/integrations/618bb4d28aac298191eec411/Lbry_Odysee.com_Responsive_Floating_DFP_Rev70_1011.js';
|
|
||||||
// $FlowFixMe
|
// $FlowFixMe
|
||||||
fjs.parentNode.insertBefore(script, fjs);
|
fjs.parentNode.insertBefore(script, fjs);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
@ -83,7 +98,7 @@ function Ads(props: Props) {
|
||||||
|
|
||||||
const videoAd = (
|
const videoAd = (
|
||||||
<div className="ads__claim-item">
|
<div className="ads__claim-item">
|
||||||
<div id="vidcrunchJS537102317" className="ads__injected-video" style={{display: 'none'}} />
|
<div id={tagNameToUse} className="ads__injected-video" style={{display: 'none'}} />
|
||||||
<div
|
<div
|
||||||
className={classnames('ads__claim-text', {
|
className={classnames('ads__claim-text', {
|
||||||
'ads__claim-text--small': small,
|
'ads__claim-text--small': small,
|
||||||
|
@ -95,24 +110,12 @@ function Ads(props: Props) {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const sidebarAd = (
|
|
||||||
<div className="ads-wrapper">
|
|
||||||
<p>Ads</p>
|
|
||||||
<p>{adsSignInDriver}</p>
|
|
||||||
<div id="vidcrunchJS537102317" />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!SHOW_ADS) {
|
if (!SHOW_ADS) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (type === 'video') {
|
if (type === 'video') {
|
||||||
return videoAd;
|
return videoAd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'sidebar') {
|
|
||||||
return sidebarAd;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(Ads);
|
export default withRouter(Ads);
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import Button from 'component/button';
|
import Button from 'component/button';
|
||||||
import { SIMPLE_SITE } from 'config';
|
import { SIMPLE_SITE } from 'config';
|
||||||
|
|
||||||
export default function Footer() {
|
export default function Footer() {
|
||||||
|
useEffect(() => {
|
||||||
|
if (!window.sp) {
|
||||||
|
document.getElementById('gdprPrivacyFooter').style.display = 'none';
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (!SIMPLE_SITE) {
|
if (!SIMPLE_SITE) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +31,10 @@ export default function Footer() {
|
||||||
<Button label={__('Terms')} href="https://odysee.com/$/tos" />
|
<Button label={__('Terms')} href="https://odysee.com/$/tos" />
|
||||||
</li>
|
</li>
|
||||||
<li className="footer__link">
|
<li className="footer__link">
|
||||||
<Button label={__('Privacy Policy')} href="https://odysee.com/$/privacypolicy" />
|
<Button label={__('Privacy Policy')} href="https://odysee.com/$/privacypolicy" />
|
||||||
|
</li>
|
||||||
|
<li className="footer__link" id="gdprPrivacyFooter">
|
||||||
|
<Button label={__('Cookies')} onClick={() => window.sp && window.sp.showPrivacyBanner()} />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
Loading…
Reference in a new issue