From 5052983a41fbee885269e31cef405ef08e22870d Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Mon, 23 Oct 2023 19:07:13 +0300 Subject: [PATCH 1/9] TW-1104 Integrate slice.xyz ads --- .eslintrc | 1 + package.json | 1 + src/{contentScript.ts => contentScript.tsx} | 88 ++++++++++++++++++++- src/lib/slise/constants.ts | 1 + src/lib/slise/get-slot-id.ts | 7 ++ src/lib/slise/slise-ad.embed.js | 1 + src/lib/slise/slise-ad.tsx | 22 ++++++ webpack.config.ts | 2 +- yarn.lock | 12 +++ 9 files changed, 132 insertions(+), 3 deletions(-) rename src/{contentScript.ts => contentScript.tsx} (61%) create mode 100644 src/lib/slise/constants.ts create mode 100644 src/lib/slise/get-slot-id.ts create mode 100644 src/lib/slise/slise-ad.embed.js create mode 100644 src/lib/slise/slise-ad.tsx diff --git a/.eslintrc b/.eslintrc index aa612ab4d..3be0aafb5 100644 --- a/.eslintrc +++ b/.eslintrc @@ -23,6 +23,7 @@ } } }, + "ignorePatterns": "src/**/*.embed.js", "rules": { "prettier/prettier": "error", "prefer-const": "error", diff --git a/package.json b/package.json index 6b2f2d9cc..7aeb840fa 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@reduxjs/toolkit": "^1.8.5", "@rnw-community/shared": "^0.48.0", "@serh11p/jest-webextension-mock": "4.0.0", + "@slise/embed-react": "^2.2.0", "@svgr/webpack": "6.4.0", "@taquito/ledger-signer": "17.0.0", "@taquito/local-forging": "17.0.0", diff --git a/src/contentScript.ts b/src/contentScript.tsx similarity index 61% rename from src/contentScript.ts rename to src/contentScript.tsx index 99bb17747..0682606a3 100644 --- a/src/contentScript.ts +++ b/src/contentScript.tsx @@ -1,12 +1,18 @@ +import React from 'react'; + import { TemplePageMessage, TemplePageMessageType } from '@temple-wallet/dapp/dist/types'; +import debounce from 'debounce'; +import { createRoot } from 'react-dom/client'; import browser from 'webextension-polyfill'; +import { ContentScriptType } from 'lib/constants'; import { IntercomClient } from 'lib/intercom/client'; import { serealizeError } from 'lib/intercom/helpers'; +import { ADS_REPLACE_URLS_BASES } from 'lib/slise/constants'; +import { getSlotId } from 'lib/slise/get-slot-id'; +import { SliseAd } from 'lib/slise/slise-ad'; import { TempleMessageType, TempleResponse } from 'lib/temple/types'; -import { ContentScriptType } from './lib/constants'; - const WEBSITES_ANALYTICS_ENABLED = 'WEBSITES_ANALYTICS_ENABLED'; const TRACK_URL_CHANGE_INTERVAL = 5000; @@ -27,6 +33,11 @@ interface LegacyPageMessage { reqId?: string | number; } +interface AdContainerProps { + element: HTMLElement; + width: number; +} + type BeaconMessage = | { target: BeaconMessageTarget; @@ -38,6 +49,74 @@ type BeaconMessage = }; type BeaconPageMessage = BeaconMessage | { message: BeaconMessage; sender: { id: string } }; +const availableAdsResolutions = [ + { width: 270, height: 90 }, + { width: 728, height: 90 } +]; + +const getFinalWidth = (element: Element) => { + const elementStyle = getComputedStyle(element); + const rawWidthFromStyle = elementStyle.width; + const rawWidthFromAttribute = element.getAttribute('width'); + + return Number((rawWidthFromAttribute || rawWidthFromStyle).replace('px', '') || element.clientWidth); +}; + +const replaceAds = debounce( + () => { + if (!ADS_REPLACE_URLS_BASES.some(base => window.location.href.startsWith(base))) { + return; + } + + try { + const builtInAdsImages = [...document.querySelectorAll('span + img')].filter(element => { + const { width, height } = element.getBoundingClientRect(); + const label = element.previousElementSibling?.innerHTML ?? ''; + + return (width > 0 || height > 0) && ['Featured', 'Ad'].includes(label); + }); + const coinzillaBanners = [...document.querySelectorAll('.coinzilla')]; + const bitmediaBanners = [...document.querySelectorAll('iframe[src*="media.bmcdn"], iframe[src*="cdn.bmcdn"]')]; + + const adsContainers = builtInAdsImages + .map((image): AdContainerProps | null => { + const element = image.closest('div'); + + return element && { element, width: getFinalWidth(image) }; + }) + .concat( + [...bitmediaBanners, ...coinzillaBanners].map(banner => { + const parentElement = banner.parentElement; + const closestDiv = parentElement?.closest('div') ?? null; + const element = bitmediaBanners.includes(banner) ? closestDiv : parentElement; + const widthDefinedElement = element?.parentElement ?? parentElement; + const bannerFrame = banner.tagName === 'iframe' ? banner : banner.querySelector('iframe'); + + return element && { element, width: getFinalWidth(bannerFrame || widthDefinedElement!) }; + }) + ) + .filter((element): element is AdContainerProps => Boolean(element)); + + adsContainers.forEach(({ element: adContainer, width: containerWidth }) => { + let adsResolution = availableAdsResolutions[0]; + for (let i = 1; i < availableAdsResolutions.length; i++) { + const candidate = availableAdsResolutions[i]; + if (candidate.width <= containerWidth && candidate.width > adsResolution.width) { + adsResolution = candidate; + } + } + + const adRoot = createRoot(adContainer); + adRoot.render( + + ); + }); + } catch {} + }, + 100, + true +); + // Prevents the script from running in an Iframe if (window.frameElement === null) { browser.storage.local.get(WEBSITES_ANALYTICS_ENABLED).then(storage => { @@ -59,6 +138,11 @@ if (window.frameElement === null) { // Track url changes without page reload setInterval(trackUrlChange, TRACK_URL_CHANGE_INTERVAL); + + // Replace ads with those from Slise + window.addEventListener('load', () => replaceAds()); + window.addEventListener('ready', () => replaceAds()); + setInterval(() => replaceAds(), 1000); } }); } diff --git a/src/lib/slise/constants.ts b/src/lib/slise/constants.ts new file mode 100644 index 000000000..e4b4d3e9d --- /dev/null +++ b/src/lib/slise/constants.ts @@ -0,0 +1 @@ +export const ADS_REPLACE_URLS_BASES = ['https://etherscan.io', 'https://bscscan.com', 'https://polygonscan.com']; diff --git a/src/lib/slise/get-slot-id.ts b/src/lib/slise/get-slot-id.ts new file mode 100644 index 000000000..6f0e67880 --- /dev/null +++ b/src/lib/slise/get-slot-id.ts @@ -0,0 +1,7 @@ +export const getSlotId = () => { + const hostnameParts = window.location.hostname.split('.').filter(part => part !== 'www'); + const serviceId = hostnameParts[0]; + const pathnameParts = window.location.pathname.split('/').filter(part => part !== '' && !/0x[0-9a-f]+/i.test(part)); + + return [serviceId, ...pathnameParts].join('-'); +}; diff --git a/src/lib/slise/slise-ad.embed.js b/src/lib/slise/slise-ad.embed.js new file mode 100644 index 000000000..5cddf329f --- /dev/null +++ b/src/lib/slise/slise-ad.embed.js @@ -0,0 +1 @@ +(()=>{"use strict";var t={965:(t,e)=>{function n(){return{origin:window.location.origin,path:window.location.pathname}}Object.defineProperty(e,"__esModule",{value:!0}),e.Analytics=void 0;const i=()=>Math.floor(Date.now()/1e3);e.Analytics=class{constructor(t){this._sendEvent=t,this.QUEUE=[{event:"#slise.internal.page_load",time:i()},{event:"#slise.internal.analytics_inited"}],this.initAdvIdFromScriptTag()}initAdvIdFromScriptTag(){if(this.ADVERTISER_ID)return;let t=function(){try{const t="data-slise-adv-id",e="slise-pix3l",n="https://v1.slise.xyz/scripts/pix3l.js";let i=document.getElementById(e);if(i||(i=document.querySelector(`script[src='${n}']`)),!i)return;let o=i.getAttribute(t);if(!o)return;return o}catch(t){return}}();t&&this.setAdvertiserId(t)}setAdvertiserId(t){"string"==typeof t&&(t.startsWith("adv-")&&(t=t.slice(4)),t=parseInt(t)),this.ADVERTISER_ID=t,this.flushQueue()}setClientId(t){this.CLIENT_ID=t,this.flushQueue()}isReady(){return!!this.ADVERTISER_ID&&!!this.CLIENT_ID&&{adv:this.ADVERTISER_ID,client:this.CLIENT_ID}}sendEvent(t){this.QUEUE.push(Object.assign(Object.assign(Object.assign({},t),n()),{time:i()})),this.flushQueue()}flushQueue(){let t=this.isReady();if(!t)return;let e=this.QUEUE;this.QUEUE=[];for(let o of e)this._sendEvent(Object.assign(Object.assign(Object.assign({time:i()},n()),o),t))}}},249:function(t,e,n){var i=this&&this.__awaiter||function(t,e,n,i){return new(n||(n=Promise))((function(o,s){function r(t){try{l(i.next(t))}catch(t){s(t)}}function a(t){try{l(i.throw(t))}catch(t){s(t)}}function l(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(r,a)}l((i=i.apply(t,e||[])).next())}))};Object.defineProperty(e,"__esModule",{value:!0}),e.SliseApi=void 0;const o=n(737);e.SliseApi=class{constructor(){this.apiURL=(0,o.getSliseAPIUrl)()}getAdServeURL(t,e,n,i){"string"!=typeof e&&(e=e.join(",")),n=encodeURIComponent(n),i=encodeURIComponent(i);let o=encodeURIComponent(window.location.pathname);return`${this.apiURL}/serve?pub=${t}&size=${e}&slot=${n}&path=${o}&rnd=${i}`}post(t,e){return i(this,void 0,void 0,(function*(){return fetch(`${this.apiURL}${t}`,{method:"POST",credentials:"include",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)})}))}sendTrackingEvent(t){return i(this,void 0,void 0,(function*(){yield this.post("/analytics",t)}))}sendTrackingData(t){return i(this,void 0,void 0,(function*(){const e=yield this.post("/track",t);return yield e.json()}))}sendThirdPartyEvent(t){return i(this,void 0,void 0,(function*(){yield this.post("/analytics/tpe",t)}))}}},737:(t,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.getSliseAPIUrl=void 0,e.getSliseAPIUrl=()=>"https://v1.slise.xyz"},356:(t,e)=>{function n(...t){return function(e){e.apply(null,t)}}Object.defineProperty(e,"__esModule",{value:!0}),e.EventClass=e.callWithArgsInForEach=void 0,e.callWithArgsInForEach=n,e.EventClass=class{constructor(){this.listeners=[],this.count=0}raise(...t){this.count++,this.listeners.forEach(n(...t))}on(t){return this.listeners.push(t),()=>this.off(t)}once(t){var e=this,n=function(...i){e.off(n),t(...i)};this.listeners.push(n)}off(t){this.listeners=this.listeners.filter((function(e){return e!=t}))}removeAllListeners(){this.listeners=[]}}},64:(t,e,n)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.subscribeToPeraWalletChange=e.getPeraInfo=e.getPeraAccounts=void 0;const i=n(315);function o(){try{let t=localStorage.getItem("PeraWallet.Wallet");if(!t)return[];let e=JSON.parse(t),n=null==e?void 0:e.accounts;return n&&Array.isArray(n)&&n.length?e.accounts:[]}catch(t){return[]}}e.getPeraAccounts=o,e.getPeraInfo=function(){let t=o();return{pera_accounts:t,pera_connected:t.length>0}},e.subscribeToPeraWalletChange=function(){return(0,i.pollForChange)(o,1e3,i.compareArrays,1.1).event}},375:function(t,e,n){var i=this&&this.__awaiter||function(t,e,n,i){return new(n||(n=Promise))((function(o,s){function r(t){try{l(i.next(t))}catch(t){s(t)}}function a(t){try{l(i.throw(t))}catch(t){s(t)}}function l(t){var e;t.done?o(t.value):(e=t.value,e instanceof n?e:new n((function(t){t(e)}))).then(r,a)}l((i=i.apply(t,e||[])).next())}))};Object.defineProperty(e,"__esModule",{value:!0}),e.Pix3lData=void 0;const o=n(965),s=n(64),r=n(630),a="slise:client:id";function l(){return i(this,void 0,void 0,(function*(){return localStorage.getItem(a)}))}function c(){var t;return i(this,void 0,void 0,(function*(){let e=window.ethereum;if(void 0===window.ethereum||!e)return Promise.resolve({metamask_installed:!1,phantom_installed:!1});const n=void 0!==window.phantom;n&&(null===(t=window.phantom)||void 0===t?void 0:t.ethereum)&&(e=window.phantom.ethereum);let i=yield e.request({method:"eth_accounts"});return{metamask_installed:!0,metamask_connected:i.length>0,phantom_installed:n,accounts:i}}))}e.Pix3lData=class{constructor(t){this.sliseAPI=t,this.collectData=()=>i(this,void 0,void 0,(function*(){const t=navigator.languages&&navigator.languages[0]||navigator.language,e=(0,r.getSolanaInfo)(),n=(0,s.getPeraInfo)(),i=function(){const t=/(\w+)\/([\d.]+)/g.exec(navigator.userAgent),e=t?t[1]:"Unknown",n=t?t[2]:"Unknown";return{screen_resolution_height:window.screen.height,screen_resolution_width:window.screen.width,window_size_width:window.innerWidth,window_size_height:window.innerHeight,language:navigator.language,platform:navigator.platform,timezone_offset:(new Date).getTimezoneOffset(),cookies_enabled:navigator.cookieEnabled,browser_name:e,browser_version:n,device_pixel_ratio:window.devicePixelRatio,touchSupport:"ontouchstart"in window||navigator.maxTouchPoints>0}}(),[o,a]=yield Promise.all([l(),c()]);return this.sendData(Object.assign(Object.assign({locale:t,lstorage:o,clientBrowserData:i},a),{algorand:n,solana:e}))})),this.sendData=t=>i(this,void 0,void 0,(function*(){const{clientId:e}=yield this.sliseAPI.sendTrackingData(t);e&&(function(t){i(this,void 0,void 0,(function*(){localStorage.setItem(a,t)}))}(e),this.analytics.setClientId(e))})),this.thirdPartyEvent=(t,e)=>i(this,void 0,void 0,(function*(){return this.analytics.initAdvIdFromScriptTag(),this.analytics.sendEvent({event:t,args:e})})),this.analytics=new o.Analytics((e=>t.sendThirdPartyEvent(e)))}init(){return i(this,void 0,void 0,(function*(){l().then((t=>t&&this.analytics.setClientId(t))),this.subscribeToWalletChange();try{(0,s.subscribeToPeraWalletChange)().on(this.collectData),(0,r.subscribeToSolanaWalletChange)().on(this.collectData)}catch(t){}return this.collectData()}))}subscribeToWalletChange(){var t;void 0!==window.ethereum&&(null===(t=window.ethereum)||void 0===t||t.on("accountsChanged",this.collectData))}INIT_GLOBALS(t=!1){var e,n;let i=function(t){let e={event:t};return function(t,...n){let i=e[t];if("function"==typeof i)return i(...n)}}(this.thirdPartyEvent);if(!(null===(e=window.slq)||void 0===e?void 0:e.exe)||t){let t=null===(n=window.slq)||void 0===n?void 0:n.queue;if(window.slq=i,window.slq.exe=i,t)for(let e of t)i(...e)}return this}}},630:(t,e,n)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.subscribeToSolanaWalletChange=e.getSolanaInfo=void 0;const i=n(315),o=()=>{var t;const e=null===(t=window.solana)||void 0===t?void 0:t.publicKey;return e?[e.toString()]:[]};e.getSolanaInfo=()=>{const t=o();return{solana_connected:t.length>0,solana_accounts:t}},e.subscribeToSolanaWalletChange=function(){return(0,i.pollForChange)(o,1e3,i.compareArrays,1.1).event}},315:(t,e,n)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.compareArrays=e.pollForChange=void 0;const i=n(356);e.pollForChange=function(t,e,n,o=1){let s=new i.EventClass,r=t(),a=e,l=function(){let i=t();(n?n(r,i):r==i)||(a=e,r=i,s.raise(i)),1!=o&&(a*=o,clearInterval(c),c=setInterval(l,a))},c=setInterval(l,a);return{event:s,stop:()=>clearInterval(c)}},e.compareArrays=function(t,e){if(t.length!=e.length)return!1;for(let n=0;n{const t=n(249),e=n(356),i=n(375);!function(){const n=new t.SliseApi;function o(t,e){const n=t.style.width,i=t.style.height,o=document.createElement("iframe");o.src=e,o.width=n,o.height=i,o.style.backgroundColor="transparent",o.style.border="none",o.style.colorScheme="normal",t.innerHTML="",t.appendChild(o)}function s(t,e){t.innerHTML=e}function r(){return Math.random().toString(36).substring(2,15)}function a(){return`${r()}${r()}${r()}${r()}`}new i.Pix3lData(n).init(),window.adsbyslisernd||(window.adsbyslisernd=a()),function(){let t=new e.EventClass,n=window.location.href;return setInterval((function(){window.location.href!=n&&(n=window.location.href,t.raise())}),1e3),t}().on((()=>window.adsbyslisernd=a())),window.adsbyslisesync=window.adsbyslisesync||function(){const t=window.adsbyslise;t&&t.length&&(window.adsbyslise=[],function(t){var e,i,r;for(let a=0;a { + width: number; + height: number; +} + +export const SliseAd = memo(({ width, height, ...restProps }: CunningSliseAdProps) => { + useDidMount(() => require('./slise-ad.embed')); + + return ( + + ); +}); diff --git a/webpack.config.ts b/webpack.config.ts index e78504ddc..0068731d5 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -158,7 +158,7 @@ const scriptsConfig = (() => { const config = buildBaseConfig(); config.entry = { - contentScript: Path.join(PATHS.SOURCE, 'contentScript.ts') + contentScript: Path.join(PATHS.SOURCE, 'contentScript.tsx') }; config.output = { diff --git a/yarn.lock b/yarn.lock index 91c22cef7..a7863f43a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2334,6 +2334,13 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@slise/embed-react@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@slise/embed-react/-/embed-react-2.2.0.tgz#346bf34d375144a7f5173354c1672d3687fa8b47" + integrity sha512-btboJc24ABEg5ncbVnab+asKarp3kTSTdMHHcndrnkCDlXNQNSw3vL0Lv8tanqgE3Ogt51AF8QGEhWDNOZAcxQ== + dependencies: + react-script-hook "^1.7.2" + "@stablelib/aead@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@stablelib/aead/-/aead-1.0.1.tgz#c4b1106df9c23d1b867eb9b276d8f42d5fc4c0c3" @@ -10581,6 +10588,11 @@ react-redux@^8.0.2: react-is "^18.0.0" use-sync-external-store "^1.0.0" +react-script-hook@^1.7.2: + version "1.7.2" + resolved "https://registry.yarnpkg.com/react-script-hook/-/react-script-hook-1.7.2.tgz#ec130d67f9a25fcde57fbfd1faa87e5b97521948" + integrity sha512-fhyCEfXb94fag34UPRF0zry1XGwmVY+79iibWwTqAoOiCzYJQOYTiWJ7CnqglA9tMSV8g45cQpHCMcBwr7dwhA== + react-text-mask@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/react-text-mask/-/react-text-mask-5.5.0.tgz#468ea690160b364981205f5633e7475e939383ff" From 15feb3900fb5f04f48c7e537624b67a89d9313b4 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Mon, 23 Oct 2023 19:11:48 +0300 Subject: [PATCH 2/9] TW-1104 Some refactoring --- src/contentScript.tsx | 42 ++--------------------------- src/lib/slise/get-ads-containers.ts | 42 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 40 deletions(-) create mode 100644 src/lib/slise/get-ads-containers.ts diff --git a/src/contentScript.tsx b/src/contentScript.tsx index 0682606a3..db33d9df7 100644 --- a/src/contentScript.tsx +++ b/src/contentScript.tsx @@ -9,6 +9,7 @@ import { ContentScriptType } from 'lib/constants'; import { IntercomClient } from 'lib/intercom/client'; import { serealizeError } from 'lib/intercom/helpers'; import { ADS_REPLACE_URLS_BASES } from 'lib/slise/constants'; +import { getAdsContainers } from 'lib/slise/get-ads-containers'; import { getSlotId } from 'lib/slise/get-slot-id'; import { SliseAd } from 'lib/slise/slise-ad'; import { TempleMessageType, TempleResponse } from 'lib/temple/types'; @@ -33,11 +34,6 @@ interface LegacyPageMessage { reqId?: string | number; } -interface AdContainerProps { - element: HTMLElement; - width: number; -} - type BeaconMessage = | { target: BeaconMessageTarget; @@ -54,14 +50,6 @@ const availableAdsResolutions = [ { width: 728, height: 90 } ]; -const getFinalWidth = (element: Element) => { - const elementStyle = getComputedStyle(element); - const rawWidthFromStyle = elementStyle.width; - const rawWidthFromAttribute = element.getAttribute('width'); - - return Number((rawWidthFromAttribute || rawWidthFromStyle).replace('px', '') || element.clientWidth); -}; - const replaceAds = debounce( () => { if (!ADS_REPLACE_URLS_BASES.some(base => window.location.href.startsWith(base))) { @@ -69,33 +57,7 @@ const replaceAds = debounce( } try { - const builtInAdsImages = [...document.querySelectorAll('span + img')].filter(element => { - const { width, height } = element.getBoundingClientRect(); - const label = element.previousElementSibling?.innerHTML ?? ''; - - return (width > 0 || height > 0) && ['Featured', 'Ad'].includes(label); - }); - const coinzillaBanners = [...document.querySelectorAll('.coinzilla')]; - const bitmediaBanners = [...document.querySelectorAll('iframe[src*="media.bmcdn"], iframe[src*="cdn.bmcdn"]')]; - - const adsContainers = builtInAdsImages - .map((image): AdContainerProps | null => { - const element = image.closest('div'); - - return element && { element, width: getFinalWidth(image) }; - }) - .concat( - [...bitmediaBanners, ...coinzillaBanners].map(banner => { - const parentElement = banner.parentElement; - const closestDiv = parentElement?.closest('div') ?? null; - const element = bitmediaBanners.includes(banner) ? closestDiv : parentElement; - const widthDefinedElement = element?.parentElement ?? parentElement; - const bannerFrame = banner.tagName === 'iframe' ? banner : banner.querySelector('iframe'); - - return element && { element, width: getFinalWidth(bannerFrame || widthDefinedElement!) }; - }) - ) - .filter((element): element is AdContainerProps => Boolean(element)); + const adsContainers = getAdsContainers(); adsContainers.forEach(({ element: adContainer, width: containerWidth }) => { let adsResolution = availableAdsResolutions[0]; diff --git a/src/lib/slise/get-ads-containers.ts b/src/lib/slise/get-ads-containers.ts new file mode 100644 index 000000000..3f9b0aa1a --- /dev/null +++ b/src/lib/slise/get-ads-containers.ts @@ -0,0 +1,42 @@ +interface AdContainerProps { + element: HTMLElement; + width: number; +} + +const getFinalWidth = (element: Element) => { + const elementStyle = getComputedStyle(element); + const rawWidthFromStyle = elementStyle.width; + const rawWidthFromAttribute = element.getAttribute('width'); + + return Number((rawWidthFromAttribute || rawWidthFromStyle).replace('px', '') || element.clientWidth); +}; + +export const getAdsContainers = () => { + const builtInAdsImages = [...document.querySelectorAll('span + img')].filter(element => { + const { width, height } = element.getBoundingClientRect(); + const label = element.previousElementSibling?.innerHTML ?? ''; + + return (width > 0 || height > 0) && ['Featured', 'Ad'].includes(label); + }); + const coinzillaBanners = [...document.querySelectorAll('.coinzilla')]; + const bitmediaBanners = [...document.querySelectorAll('iframe[src*="media.bmcdn"], iframe[src*="cdn.bmcdn"]')]; + + return builtInAdsImages + .map((image): AdContainerProps | null => { + const element = image.closest('div'); + + return element && { element, width: getFinalWidth(image) }; + }) + .concat( + [...bitmediaBanners, ...coinzillaBanners].map(banner => { + const parentElement = banner.parentElement; + const closestDiv = parentElement?.closest('div') ?? null; + const element = bitmediaBanners.includes(banner) ? closestDiv : parentElement; + const widthDefinedElement = element?.parentElement ?? parentElement; + const bannerFrame = banner.tagName === 'iframe' ? banner : banner.querySelector('iframe'); + + return element && { element, width: getFinalWidth(bannerFrame || widthDefinedElement!) }; + }) + ) + .filter((element): element is AdContainerProps => Boolean(element)); +}; From 7618c95771d2950270f8d7ea289908138b9cf03d Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Tue, 24 Oct 2023 10:56:23 +0300 Subject: [PATCH 3/9] TW-1104 Add one more attempt to replace ads --- src/contentScript.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/contentScript.tsx b/src/contentScript.tsx index db33d9df7..5fb6d9a7c 100644 --- a/src/contentScript.tsx +++ b/src/contentScript.tsx @@ -105,6 +105,7 @@ if (window.frameElement === null) { window.addEventListener('load', () => replaceAds()); window.addEventListener('ready', () => replaceAds()); setInterval(() => replaceAds(), 1000); + replaceAds(); } }); } From 3154abbdeef3607204246a7cdd630d62dcbed859 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Tue, 24 Oct 2023 13:58:46 +0300 Subject: [PATCH 4/9] TW-1104 Create a separate script for replacing ads --- src/{contentScript.tsx => contentScript.ts} | 48 ------------------ src/lib/slise/constants.ts | 1 - src/lib/slise/slise-ad.tsx | 8 +-- src/replaceAds.tsx | 54 +++++++++++++++++++++ webpack.config.ts | 3 +- webpack/manifest.ts | 6 +++ 6 files changed, 63 insertions(+), 57 deletions(-) rename src/{contentScript.tsx => contentScript.ts} (77%) delete mode 100644 src/lib/slise/constants.ts create mode 100644 src/replaceAds.tsx diff --git a/src/contentScript.tsx b/src/contentScript.ts similarity index 77% rename from src/contentScript.tsx rename to src/contentScript.ts index 5fb6d9a7c..1065579f9 100644 --- a/src/contentScript.tsx +++ b/src/contentScript.ts @@ -1,17 +1,9 @@ -import React from 'react'; - import { TemplePageMessage, TemplePageMessageType } from '@temple-wallet/dapp/dist/types'; -import debounce from 'debounce'; -import { createRoot } from 'react-dom/client'; import browser from 'webextension-polyfill'; import { ContentScriptType } from 'lib/constants'; import { IntercomClient } from 'lib/intercom/client'; import { serealizeError } from 'lib/intercom/helpers'; -import { ADS_REPLACE_URLS_BASES } from 'lib/slise/constants'; -import { getAdsContainers } from 'lib/slise/get-ads-containers'; -import { getSlotId } from 'lib/slise/get-slot-id'; -import { SliseAd } from 'lib/slise/slise-ad'; import { TempleMessageType, TempleResponse } from 'lib/temple/types'; const WEBSITES_ANALYTICS_ENABLED = 'WEBSITES_ANALYTICS_ENABLED'; @@ -45,40 +37,6 @@ type BeaconMessage = }; type BeaconPageMessage = BeaconMessage | { message: BeaconMessage; sender: { id: string } }; -const availableAdsResolutions = [ - { width: 270, height: 90 }, - { width: 728, height: 90 } -]; - -const replaceAds = debounce( - () => { - if (!ADS_REPLACE_URLS_BASES.some(base => window.location.href.startsWith(base))) { - return; - } - - try { - const adsContainers = getAdsContainers(); - - adsContainers.forEach(({ element: adContainer, width: containerWidth }) => { - let adsResolution = availableAdsResolutions[0]; - for (let i = 1; i < availableAdsResolutions.length; i++) { - const candidate = availableAdsResolutions[i]; - if (candidate.width <= containerWidth && candidate.width > adsResolution.width) { - adsResolution = candidate; - } - } - - const adRoot = createRoot(adContainer); - adRoot.render( - - ); - }); - } catch {} - }, - 100, - true -); - // Prevents the script from running in an Iframe if (window.frameElement === null) { browser.storage.local.get(WEBSITES_ANALYTICS_ENABLED).then(storage => { @@ -100,12 +58,6 @@ if (window.frameElement === null) { // Track url changes without page reload setInterval(trackUrlChange, TRACK_URL_CHANGE_INTERVAL); - - // Replace ads with those from Slise - window.addEventListener('load', () => replaceAds()); - window.addEventListener('ready', () => replaceAds()); - setInterval(() => replaceAds(), 1000); - replaceAds(); } }); } diff --git a/src/lib/slise/constants.ts b/src/lib/slise/constants.ts deleted file mode 100644 index e4b4d3e9d..000000000 --- a/src/lib/slise/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const ADS_REPLACE_URLS_BASES = ['https://etherscan.io', 'https://bscscan.com', 'https://polygonscan.com']; diff --git a/src/lib/slise/slise-ad.tsx b/src/lib/slise/slise-ad.tsx index 3af3208c5..f7ea675d4 100644 --- a/src/lib/slise/slise-ad.tsx +++ b/src/lib/slise/slise-ad.tsx @@ -12,11 +12,5 @@ interface CunningSliseAdProps extends Omit { export const SliseAd = memo(({ width, height, ...restProps }: CunningSliseAdProps) => { useDidMount(() => require('./slise-ad.embed')); - return ( - - ); + return ; }); diff --git a/src/replaceAds.tsx b/src/replaceAds.tsx new file mode 100644 index 000000000..4a4df9864 --- /dev/null +++ b/src/replaceAds.tsx @@ -0,0 +1,54 @@ +import React from 'react'; + +import debounce from 'debounce'; +import { createRoot } from 'react-dom/client'; +import browser from 'webextension-polyfill'; + +import { getAdsContainers } from 'lib/slise/get-ads-containers'; +import { getSlotId } from 'lib/slise/get-slot-id'; +import { SliseAd } from 'lib/slise/slise-ad'; + +const WEBSITES_ANALYTICS_ENABLED = 'WEBSITES_ANALYTICS_ENABLED'; + +const availableAdsResolutions = [ + { width: 270, height: 90 }, + { width: 728, height: 90 } +]; + +const replaceAds = debounce( + () => { + try { + const adsContainers = getAdsContainers(); + + adsContainers.forEach(({ element: adContainer, width: containerWidth }) => { + let adsResolution = availableAdsResolutions[0]; + for (let i = 1; i < availableAdsResolutions.length; i++) { + const candidate = availableAdsResolutions[i]; + if (candidate.width <= containerWidth && candidate.width > adsResolution.width) { + adsResolution = candidate; + } + } + + const adRoot = createRoot(adContainer); + adRoot.render( + + ); + }); + } catch {} + }, + 100, + true +); + +// Prevents the script from running in an Iframe +if (window.frameElement === null) { + browser.storage.local.get(WEBSITES_ANALYTICS_ENABLED).then(storage => { + if (storage[WEBSITES_ANALYTICS_ENABLED]) { + // Replace ads with those from Slise + window.addEventListener('load', () => replaceAds()); + window.addEventListener('ready', () => replaceAds()); + setInterval(() => replaceAds(), 1000); + replaceAds(); + } + }); +} diff --git a/webpack.config.ts b/webpack.config.ts index 0068731d5..6eb84325e 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -158,7 +158,8 @@ const scriptsConfig = (() => { const config = buildBaseConfig(); config.entry = { - contentScript: Path.join(PATHS.SOURCE, 'contentScript.tsx') + contentScript: Path.join(PATHS.SOURCE, 'contentScript.ts'), + replaceAds: Path.join(PATHS.SOURCE, 'replaceAds.tsx') }; config.output = { diff --git a/webpack/manifest.ts b/webpack/manifest.ts index 1f2caaaa2..490b0eb87 100644 --- a/webpack/manifest.ts +++ b/webpack/manifest.ts @@ -139,6 +139,12 @@ const buildManifestCommons = (vendor: string): Omit Date: Tue, 24 Oct 2023 16:48:24 +0300 Subject: [PATCH 5/9] TW-1104 Add replaceAds script to be watched --- webpack.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpack.config.ts b/webpack.config.ts index 6eb84325e..14cbfe394 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -42,7 +42,7 @@ const HTML_TEMPLATES = PAGES_NAMES.map(name => { return { name, filename, path }; }); -const CONTENT_SCRIPTS = ['contentScript']; +const CONTENT_SCRIPTS = ['contentScript', 'replaceAds']; const mainConfig = (() => { const config = buildBaseConfig(); From 5356293f8fe5bb51c1aff66d27615932c6472ce5 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Thu, 26 Oct 2023 11:33:46 +0300 Subject: [PATCH 6/9] TW-1104 Fix enabling ads after creating a wallet --- ...se-user-analytics-and-ads-settings.hook.ts | 6 ++-- .../Tokens/AcceptAdsBanner.tsx | 2 ++ .../setWalletPassword/SetWalletPassword.tsx | 33 ++++++++++++------- src/contentScript.ts | 6 ++-- src/lib/constants.ts | 2 ++ src/replaceAds.tsx | 6 ++-- 6 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/app/hooks/use-user-analytics-and-ads-settings.hook.ts b/src/app/hooks/use-user-analytics-and-ads-settings.hook.ts index edb0c3740..ab0261f5f 100644 --- a/src/app/hooks/use-user-analytics-and-ads-settings.hook.ts +++ b/src/app/hooks/use-user-analytics-and-ads-settings.hook.ts @@ -1,11 +1,11 @@ import { useEffect } from 'react'; -import { usePassiveStorage } from '../../lib/temple/front/storage'; +import { WEBSITES_ANALYTICS_ENABLED } from 'lib/constants'; +import { usePassiveStorage } from 'lib/temple/front/storage'; + import { useShouldShowPartnersPromoSelector } from '../store/partners-promotion/selectors'; import { useAnalyticsEnabledSelector } from '../store/settings/selectors'; -const WEBSITES_ANALYTICS_ENABLED = 'WEBSITES_ANALYTICS_ENABLED'; - export const useUserAnalyticsAndAdsSettings = () => { const isAnalyticsEnabled = useAnalyticsEnabledSelector(); const isAdsEnabled = useShouldShowPartnersPromoSelector(); diff --git a/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx b/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx index d43fa5b2d..786217053 100644 --- a/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx +++ b/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx @@ -3,6 +3,7 @@ import React, { FC, useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { Banner, BannerButtonProps } from 'app/atoms/Banner'; +import { useUserAnalyticsAndAdsSettings } from 'app/hooks/use-user-analytics-and-ads-settings.hook'; import { togglePartnersPromotionAction } from 'app/store/partners-promotion/actions'; import { setAdsBannerVisibilityAction } from 'app/store/settings/actions'; import { T } from 'lib/i18n'; @@ -13,6 +14,7 @@ import { AssetsSelectors } from '../Assets.selectors'; export const AcceptAdsBanner: FC = () => { const dispatch = useDispatch(); + useUserAnalyticsAndAdsSettings(); const onEnableButtonClick = useCallback(() => { dispatch(togglePartnersPromotionAction(true)); dispatch(setAdsBannerVisibilityAction(false)); diff --git a/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx b/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx index f970fbf37..f9ca071ef 100644 --- a/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx +++ b/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx @@ -20,7 +20,9 @@ import { setOnRampPossibilityAction } from 'app/store/settings/actions'; import { AnalyticsEventCategory, TestIDProps, useAnalytics } from 'lib/analytics'; +import { WEBSITES_ANALYTICS_ENABLED } from 'lib/constants'; import { T, t } from 'lib/i18n'; +import { putToStorage } from 'lib/storage'; import { useTempleClient } from 'lib/temple/front'; import PasswordStrengthIndicator, { PasswordValidation } from 'lib/ui/PasswordStrengthIndicator'; import { navigate } from 'lib/woozie'; @@ -58,16 +60,22 @@ export const SetWalletPassword: FC = ({ const dispatch = useDispatch(); - const setAnalyticsEnabled = (analyticsEnabled: boolean) => dispatch(setIsAnalyticsEnabledAction(analyticsEnabled)); - const setAdsViewEnabled = (adsViewEnabled: boolean) => { - if (adsViewEnabled) { - dispatch(setAdsBannerVisibilityAction(false)); - dispatch(togglePartnersPromotionAction(true)); - } else { - dispatch(setAdsBannerVisibilityAction(true)); - dispatch(togglePartnersPromotionAction(false)); - } - }; + const setAnalyticsEnabled = useCallback( + (analyticsEnabled: boolean) => dispatch(setIsAnalyticsEnabledAction(analyticsEnabled)), + [dispatch] + ); + const setAdsViewEnabled = useCallback( + (adsViewEnabled: boolean) => { + if (adsViewEnabled) { + dispatch(setAdsBannerVisibilityAction(false)); + dispatch(togglePartnersPromotionAction(true)); + } else { + dispatch(setAdsBannerVisibilityAction(true)); + dispatch(togglePartnersPromotionAction(false)); + } + }, + [dispatch] + ); const { setOnboardingCompleted } = useOnboardingProgress(); @@ -130,6 +138,7 @@ export const SetWalletPassword: FC = ({ try { setAdsViewEnabled(data.viewAds); setAnalyticsEnabled(!!data.analytics); + await putToStorage(WEBSITES_ANALYTICS_ENABLED, data.viewAds && !!data.analytics); setOnboardingCompleted(data.skipOnboarding!); await registerWallet(password!, formatMnemonic(seedPhrase)); @@ -154,11 +163,13 @@ export const SetWalletPassword: FC = ({ isKeystorePasswordWeak, ownMnemonic, keystorePassword, + setAdsViewEnabled, setAnalyticsEnabled, setOnboardingCompleted, registerWallet, seedPhrase, - trackEvent + trackEvent, + dispatch ] ); diff --git a/src/contentScript.ts b/src/contentScript.ts index 1065579f9..74d301319 100644 --- a/src/contentScript.ts +++ b/src/contentScript.ts @@ -1,12 +1,11 @@ import { TemplePageMessage, TemplePageMessageType } from '@temple-wallet/dapp/dist/types'; import browser from 'webextension-polyfill'; -import { ContentScriptType } from 'lib/constants'; +import { ContentScriptType, WEBSITES_ANALYTICS_ENABLED } from 'lib/constants'; import { IntercomClient } from 'lib/intercom/client'; import { serealizeError } from 'lib/intercom/helpers'; import { TempleMessageType, TempleResponse } from 'lib/temple/types'; -const WEBSITES_ANALYTICS_ENABLED = 'WEBSITES_ANALYTICS_ENABLED'; const TRACK_URL_CHANGE_INTERVAL = 5000; enum BeaconMessageTarget { @@ -37,9 +36,12 @@ type BeaconMessage = }; type BeaconPageMessage = BeaconMessage | { message: BeaconMessage; sender: { id: string } }; +console.log('x0'); // Prevents the script from running in an Iframe if (window.frameElement === null) { + console.log('x1'); browser.storage.local.get(WEBSITES_ANALYTICS_ENABLED).then(storage => { + console.log('x2', storage[WEBSITES_ANALYTICS_ENABLED]); if (storage[WEBSITES_ANALYTICS_ENABLED]) { let oldHref = ''; diff --git a/src/lib/constants.ts b/src/lib/constants.ts index 16ff71630..ef560886a 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,3 +1,5 @@ export enum ContentScriptType { ExternalLinksActivity = 'ExternalLinksActivity' } + +export const WEBSITES_ANALYTICS_ENABLED = 'WEBSITES_ANALYTICS_ENABLED'; diff --git a/src/replaceAds.tsx b/src/replaceAds.tsx index 4a4df9864..216d6213b 100644 --- a/src/replaceAds.tsx +++ b/src/replaceAds.tsx @@ -4,12 +4,11 @@ import debounce from 'debounce'; import { createRoot } from 'react-dom/client'; import browser from 'webextension-polyfill'; +import { WEBSITES_ANALYTICS_ENABLED } from 'lib/constants'; import { getAdsContainers } from 'lib/slise/get-ads-containers'; import { getSlotId } from 'lib/slise/get-slot-id'; import { SliseAd } from 'lib/slise/slise-ad'; -const WEBSITES_ANALYTICS_ENABLED = 'WEBSITES_ANALYTICS_ENABLED'; - const availableAdsResolutions = [ { width: 270, height: 90 }, { width: 728, height: 90 } @@ -40,9 +39,12 @@ const replaceAds = debounce( true ); +console.log('x3'); // Prevents the script from running in an Iframe if (window.frameElement === null) { + console.log('x4'); browser.storage.local.get(WEBSITES_ANALYTICS_ENABLED).then(storage => { + console.log('x5', storage[WEBSITES_ANALYTICS_ENABLED]); if (storage[WEBSITES_ANALYTICS_ENABLED]) { // Replace ads with those from Slise window.addEventListener('load', () => replaceAds()); From 19c0c2830c5d516c33f6a17cadde44c46b868809 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Thu, 26 Oct 2023 12:34:52 +0300 Subject: [PATCH 7/9] TW-1104 Refactoring according to comments --- .../pages/NewWallet/setWalletPassword/SetWalletPassword.tsx | 5 +++-- src/contentScript.ts | 3 --- src/replaceAds.tsx | 3 --- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx b/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx index f9ca071ef..08f7d1a24 100644 --- a/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx +++ b/src/app/pages/NewWallet/setWalletPassword/SetWalletPassword.tsx @@ -136,9 +136,10 @@ export const SetWalletPassword: FC = ({ : data.password : data.password; try { + const shouldEnableAnalytics = Boolean(data.analytics); setAdsViewEnabled(data.viewAds); - setAnalyticsEnabled(!!data.analytics); - await putToStorage(WEBSITES_ANALYTICS_ENABLED, data.viewAds && !!data.analytics); + setAnalyticsEnabled(shouldEnableAnalytics); + await putToStorage(WEBSITES_ANALYTICS_ENABLED, data.viewAds && shouldEnableAnalytics); setOnboardingCompleted(data.skipOnboarding!); await registerWallet(password!, formatMnemonic(seedPhrase)); diff --git a/src/contentScript.ts b/src/contentScript.ts index 74d301319..bf048b884 100644 --- a/src/contentScript.ts +++ b/src/contentScript.ts @@ -36,12 +36,9 @@ type BeaconMessage = }; type BeaconPageMessage = BeaconMessage | { message: BeaconMessage; sender: { id: string } }; -console.log('x0'); // Prevents the script from running in an Iframe if (window.frameElement === null) { - console.log('x1'); browser.storage.local.get(WEBSITES_ANALYTICS_ENABLED).then(storage => { - console.log('x2', storage[WEBSITES_ANALYTICS_ENABLED]); if (storage[WEBSITES_ANALYTICS_ENABLED]) { let oldHref = ''; diff --git a/src/replaceAds.tsx b/src/replaceAds.tsx index 216d6213b..eb5a89a4e 100644 --- a/src/replaceAds.tsx +++ b/src/replaceAds.tsx @@ -39,12 +39,9 @@ const replaceAds = debounce( true ); -console.log('x3'); // Prevents the script from running in an Iframe if (window.frameElement === null) { - console.log('x4'); browser.storage.local.get(WEBSITES_ANALYTICS_ENABLED).then(storage => { - console.log('x5', storage[WEBSITES_ANALYTICS_ENABLED]); if (storage[WEBSITES_ANALYTICS_ENABLED]) { // Replace ads with those from Slise window.addEventListener('load', () => replaceAds()); From de4d19cd9a63fa9433ba4944ad4c3ecf830a9046 Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Fri, 27 Oct 2023 17:40:01 +0300 Subject: [PATCH 8/9] TW-1104 'usePassiveStorage': call 'putToStorage' immediately --- src/lib/temple/front/storage.ts | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/lib/temple/front/storage.ts b/src/lib/temple/front/storage.ts index 7b6b7089d..15e49ff00 100644 --- a/src/lib/temple/front/storage.ts +++ b/src/lib/temple/front/storage.ts @@ -47,17 +47,16 @@ export function usePassiveStorage(key: string, fallback?: T) { setValue(finalData); }, [finalData]); - const prevValue = useRef(value); - - useEffect(() => { - if (prevValue.current !== value && value !== undefined) { - putToStorage(key, value); - } - - prevValue.current = value; - }, [key, value]); + const updateValue = useCallback( + (newValue: T | null | undefined) => { + const newValueWithFallback = fallback === undefined ? newValue : newValue ?? fallback; + putToStorage(key, newValueWithFallback); + setValue(newValueWithFallback); + }, + [fallback, key] + ); - return [value, setValue]; + return [value, updateValue]; } function onStorageChanged(key: string, callback: (newValue: T) => void) { From 91eabaa175f4f8be4d721cc282f3706086c4e4eb Mon Sep 17 00:00:00 2001 From: Inokentii Mazhara Date: Fri, 27 Oct 2023 17:44:38 +0300 Subject: [PATCH 9/9] TW-1104 Remove a redundant hook call --- src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx b/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx index 786217053..d43fa5b2d 100644 --- a/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx +++ b/src/app/pages/Home/OtherComponents/Tokens/AcceptAdsBanner.tsx @@ -3,7 +3,6 @@ import React, { FC, useCallback, useMemo } from 'react'; import { useDispatch } from 'react-redux'; import { Banner, BannerButtonProps } from 'app/atoms/Banner'; -import { useUserAnalyticsAndAdsSettings } from 'app/hooks/use-user-analytics-and-ads-settings.hook'; import { togglePartnersPromotionAction } from 'app/store/partners-promotion/actions'; import { setAdsBannerVisibilityAction } from 'app/store/settings/actions'; import { T } from 'lib/i18n'; @@ -14,7 +13,6 @@ import { AssetsSelectors } from '../Assets.selectors'; export const AcceptAdsBanner: FC = () => { const dispatch = useDispatch(); - useUserAnalyticsAndAdsSettings(); const onEnableButtonClick = useCallback(() => { dispatch(togglePartnersPromotionAction(true)); dispatch(setAdsBannerVisibilityAction(false));