Commit 8f72fe60 authored by isstuev's avatar isstuev

Add AdButler as an additional ad provider

parent 9cdbf6d6
import type { Feature } from './types'; import type { Feature } from './types';
import type { AdButlerConfig } from 'types/client/adButlerConfig'; import type { AdButlerConfig } from 'types/client/adButlerConfig';
import { SUPPORTED_AD_BANNER_PROVIDERS } from 'types/client/adProviders'; import { SUPPORTED_AD_BANNER_PROVIDERS } from 'types/client/adProviders';
import type { AdBannerProviders } from 'types/client/adProviders'; import type { AdBannerProviders, AdBannerAdditionalProviders } from 'types/client/adProviders';
import { getEnvValue, parseEnvJson } from '../utils'; import { getEnvValue, parseEnvJson } from '../utils';
...@@ -11,6 +11,8 @@ const provider: AdBannerProviders = (() => { ...@@ -11,6 +11,8 @@ const provider: AdBannerProviders = (() => {
return envValue && SUPPORTED_AD_BANNER_PROVIDERS.includes(envValue) ? envValue : 'slise'; return envValue && SUPPORTED_AD_BANNER_PROVIDERS.includes(envValue) ? envValue : 'slise';
})(); })();
const additionalProvider = getEnvValue('NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER') as AdBannerAdditionalProviders;
const title = 'Banner ads'; const title = 'Banner ads';
type AdsBannerFeaturePayload = { type AdsBannerFeaturePayload = {
...@@ -23,6 +25,15 @@ type AdsBannerFeaturePayload = { ...@@ -23,6 +25,15 @@ type AdsBannerFeaturePayload = {
mobile: AdButlerConfig; mobile: AdButlerConfig;
}; };
}; };
} | {
provider: Exclude<AdBannerProviders, 'adbutler' | 'none'>;
additionalProvider: 'adbutler';
adButler: {
config: {
desktop: AdButlerConfig;
mobile: AdButlerConfig;
};
};
} }
const config: Feature<AdsBannerFeaturePayload> = (() => { const config: Feature<AdsBannerFeaturePayload> = (() => {
...@@ -44,6 +55,24 @@ const config: Feature<AdsBannerFeaturePayload> = (() => { ...@@ -44,6 +55,24 @@ const config: Feature<AdsBannerFeaturePayload> = (() => {
}); });
} }
} else if (provider !== 'none') { } else if (provider !== 'none') {
if (additionalProvider === 'adbutler') {
const desktopConfig = parseEnvJson<AdButlerConfig>(getEnvValue('NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP'));
const mobileConfig = parseEnvJson<AdButlerConfig>(getEnvValue('NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE'));
return Object.freeze({
title,
isEnabled: true,
provider,
additionalProvider,
adButler: {
config: {
desktop: desktopConfig,
mobile: mobileConfig,
},
},
});
}
return Object.freeze({ return Object.freeze({
title, title,
isEnabled: true, isEnabled: true,
......
...@@ -9,8 +9,8 @@ declare module 'yup' { ...@@ -9,8 +9,8 @@ declare module 'yup' {
import * as yup from 'yup'; import * as yup from 'yup';
import type { AdButlerConfig } from '../../../types/client/adButlerConfig'; import type { AdButlerConfig } from '../../../types/client/adButlerConfig';
import { SUPPORTED_AD_TEXT_PROVIDERS, SUPPORTED_AD_BANNER_PROVIDERS } from '../../../types/client/adProviders'; import { SUPPORTED_AD_TEXT_PROVIDERS, SUPPORTED_AD_BANNER_PROVIDERS, SUPPORTED_AD_BANNER_ADDITIONAL_PROVIDERS } from '../../../types/client/adProviders';
import type { AdTextProviders, AdBannerProviders } from '../../../types/client/adProviders'; import type { AdTextProviders, AdBannerProviders, AdBannerAdditionalProviders } from '../../../types/client/adProviders';
import type { ContractCodeIde } from '../../../types/client/contract'; import type { ContractCodeIde } from '../../../types/client/contract';
import { GAS_UNITS } from '../../../types/client/gasTracker'; import { GAS_UNITS } from '../../../types/client/gasTracker';
import type { GasUnit } from '../../../types/client/gasTracker'; import type { GasUnit } from '../../../types/client/gasTracker';
...@@ -176,12 +176,23 @@ const adButlerConfigSchema = yup ...@@ -176,12 +176,23 @@ const adButlerConfigSchema = yup
height: yup.number().positive().required(), height: yup.number().positive().required(),
}) })
.required(), .required(),
})
.when('NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER', {
is: (value: AdBannerProviders) => value === 'adbutler',
then: (schema) => schema
.shape({
id: yup.string().required(),
width: yup.number().positive().required(),
height: yup.number().positive().required(),
})
.required(),
}); });
const adsBannerSchema = yup const adsBannerSchema = yup
.object() .object()
.shape({ .shape({
NEXT_PUBLIC_AD_BANNER_PROVIDER: yup.string<AdBannerProviders>().oneOf(SUPPORTED_AD_BANNER_PROVIDERS), NEXT_PUBLIC_AD_BANNER_PROVIDER: yup.string<AdBannerProviders>().oneOf(SUPPORTED_AD_BANNER_PROVIDERS),
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER: yup.string<AdBannerAdditionalProviders>().oneOf(SUPPORTED_AD_BANNER_ADDITIONAL_PROVIDERS),
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP: adButlerConfigSchema, NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP: adButlerConfigSchema,
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: adButlerConfigSchema, NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: adButlerConfigSchema,
}); });
......
NEXT_PUBLIC_AD_BANNER_PROVIDER='slise'
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER='adbutler'
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP={'id':'123456','width':'728','height':'90'}
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE={'id':'654321','width':'300','height':'100'}
\ No newline at end of file
...@@ -82,6 +82,9 @@ frontend: ...@@ -82,6 +82,9 @@ frontend:
NEXT_PUBLIC_SWAP_BUTTON_URL: uniswap NEXT_PUBLIC_SWAP_BUTTON_URL: uniswap
NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS: true NEXT_PUBLIC_HAS_CONTRACT_AUDIT_REPORTS: true
NEXT_PUBLIC_AD_BANNER_PROVIDER: getit NEXT_PUBLIC_AD_BANNER_PROVIDER: getit
NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER: adbutler
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP: "{ \"id\": \"632019\", \"width\": \"728\", \"height\": \"90\" }"
NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE: "{ \"id\": \"632018\", \"width\": \"320\", \"height\": \"100\" }"
envFromSecret: envFromSecret:
NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN NEXT_PUBLIC_SENTRY_DSN: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/NEXT_PUBLIC_SENTRY_DSN
SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI SENTRY_CSP_REPORT_URI: ref+vault://deployment-values/blockscout/dev/review?token_env=VAULT_TOKEN&address=https://vault.k8s.blockscout.com#/SENTRY_CSP_REPORT_URI
......
...@@ -352,6 +352,7 @@ This feature is **enabled by default** with the `slise` ads provider. To switch ...@@ -352,6 +352,7 @@ This feature is **enabled by default** with the `slise` ads provider. To switch
| Variable | Type| Description | Compulsoriness | Default value | Example value | | Variable | Type| Description | Compulsoriness | Default value | Example value |
| --- | --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- | --- |
| NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `hype` \| `getit` \| `none` | Ads provider | - | `slise` | `coinzilla` | | NEXT_PUBLIC_AD_BANNER_PROVIDER | `slise` \| `adbutler` \| `coinzilla` \| `hype` \| `getit` \| `none` | Ads provider | - | `slise` | `coinzilla` |
| NEXT_PUBLIC_AD_BANNER_ADDITIONAL_PROVIDER | `adbutler` | Additional ads provider to mix with the main one | - | - | `adbutler` |
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP | `{ id: string; width: string; height: string }` | Placement config for desktop Adbutler banner | - | - | `{'id':'123456','width':'728','height':'90'}` | | NEXT_PUBLIC_AD_ADBUTLER_CONFIG_DESKTOP | `{ id: string; width: string; height: string }` | Placement config for desktop Adbutler banner | - | - | `{'id':'123456','width':'728','height':'90'}` |
| NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE | `{ id: string; width: number; height: number }` | Placement config for mobile Adbutler banner | - | - | `{'id':'654321','width':'300','height':'100'}` | | NEXT_PUBLIC_AD_ADBUTLER_CONFIG_MOBILE | `{ id: string; width: number; height: number }` | Placement config for mobile Adbutler banner | - | - | `{'id':'654321','width':'300','height':'100'}` |
......
...@@ -2,6 +2,7 @@ import type { GetServerSideProps } from 'next'; ...@@ -2,6 +2,7 @@ import type { GetServerSideProps } from 'next';
import config from 'configs/app'; import config from 'configs/app';
const rollupFeature = config.features.rollup; const rollupFeature = config.features.rollup;
const adBannerFeature = config.features.adsBanner;
export type Props = { export type Props = {
cookies: string; cookies: string;
...@@ -12,9 +13,22 @@ export type Props = { ...@@ -12,9 +13,22 @@ export type Props = {
number: string; number: string;
q: string; q: string;
name: string; name: string;
adBannerProvider?: string;
} }
export const base: GetServerSideProps<Props> = async({ req, query }) => { export const base: GetServerSideProps<Props> = async({ req, query }) => {
const adBannerProvider = (() => {
if (adBannerFeature.isEnabled) {
if ('additionalProvider' in adBannerFeature && adBannerFeature.additionalProvider) {
// we need to get a random ad provider on the server side to keep it consistent with the client side
const randomIndex = Math.round(Math.random());
return [ adBannerFeature.provider, adBannerFeature.additionalProvider ][randomIndex];
} else {
return adBannerFeature.provider;
}
}
})();
return { return {
props: { props: {
cookies: req.headers.cookie || '', cookies: req.headers.cookie || '',
...@@ -25,6 +39,7 @@ export const base: GetServerSideProps<Props> = async({ req, query }) => { ...@@ -25,6 +39,7 @@ export const base: GetServerSideProps<Props> = async({ req, query }) => {
number: query.number?.toString() || '', number: query.number?.toString() || '',
q: query.q?.toString() || '', q: query.q?.toString() || '',
name: query.name?.toString() || '', name: query.name?.toString() || '',
adBannerProvider,
}, },
}; };
}; };
......
...@@ -3,5 +3,8 @@ import type { ArrayElement } from 'types/utils'; ...@@ -3,5 +3,8 @@ import type { ArrayElement } from 'types/utils';
export const SUPPORTED_AD_BANNER_PROVIDERS = [ 'slise', 'adbutler', 'coinzilla', 'hype', 'getit', 'none' ] as const; export const SUPPORTED_AD_BANNER_PROVIDERS = [ 'slise', 'adbutler', 'coinzilla', 'hype', 'getit', 'none' ] as const;
export type AdBannerProviders = ArrayElement<typeof SUPPORTED_AD_BANNER_PROVIDERS>; export type AdBannerProviders = ArrayElement<typeof SUPPORTED_AD_BANNER_PROVIDERS>;
export const SUPPORTED_AD_BANNER_ADDITIONAL_PROVIDERS = [ 'adbutler' ] as const;
export type AdBannerAdditionalProviders = ArrayElement<typeof SUPPORTED_AD_BANNER_ADDITIONAL_PROVIDERS>;
export const SUPPORTED_AD_TEXT_PROVIDERS = [ 'coinzilla', 'none' ] as const; export const SUPPORTED_AD_TEXT_PROVIDERS = [ 'coinzilla', 'none' ] as const;
export type AdTextProviders = ArrayElement<typeof SUPPORTED_AD_TEXT_PROVIDERS>; export type AdTextProviders = ArrayElement<typeof SUPPORTED_AD_TEXT_PROVIDERS>;
...@@ -14,14 +14,16 @@ import SliseBanner from './SliseBanner'; ...@@ -14,14 +14,16 @@ import SliseBanner from './SliseBanner';
const feature = config.features.adsBanner; const feature = config.features.adsBanner;
const AdBanner = ({ className, isLoading }: { className?: string; isLoading?: boolean }) => { const AdBanner = ({ className, isLoading }: { className?: string; isLoading?: boolean }) => {
const provider = useAppContext().adBannerProvider;
const hasAdblockCookie = cookies.get(cookies.NAMES.ADBLOCK_DETECTED, useAppContext().cookies); const hasAdblockCookie = cookies.get(cookies.NAMES.ADBLOCK_DETECTED, useAppContext().cookies);
if (!feature.isEnabled || hasAdblockCookie) { if (!feature.isEnabled || hasAdblockCookie || !provider) {
return null; return null;
} }
const content = (() => { const content = (() => {
switch (feature.provider) { switch (provider) {
case 'adbutler': case 'adbutler':
return <AdbutlerBanner/>; return <AdbutlerBanner/>;
case 'coinzilla': case 'coinzilla':
...@@ -40,7 +42,7 @@ const AdBanner = ({ className, isLoading }: { className?: string; isLoading?: bo ...@@ -40,7 +42,7 @@ const AdBanner = ({ className, isLoading }: { className?: string; isLoading?: bo
className={ className } className={ className }
isLoaded={ !isLoading } isLoaded={ !isLoading }
borderRadius="none" borderRadius="none"
maxW={ feature.provider === 'adbutler' ? feature.adButler.config.desktop.width : '728px' } maxW={ ('adButler' in feature && feature.adButler) ? feature.adButler.config.desktop.width : '728px' }
w="100%" w="100%"
> >
{ content } { content }
......
...@@ -13,8 +13,9 @@ const feature = config.features.adsBanner; ...@@ -13,8 +13,9 @@ const feature = config.features.adsBanner;
const AdbutlerBanner = ({ className }: { className?: string }) => { const AdbutlerBanner = ({ className }: { className?: string }) => {
const router = useRouter(); const router = useRouter();
const isMobile = useIsMobile(); const isMobile = useIsMobile();
React.useEffect(() => { React.useEffect(() => {
if (!feature.isEnabled || feature.provider !== 'adbutler') { if (!('adButler' in feature)) {
return; return;
} }
......
...@@ -8,7 +8,7 @@ export const connectAdbutler = `if (!window.AdButler){(function(){var s = docume ...@@ -8,7 +8,7 @@ export const connectAdbutler = `if (!window.AdButler){(function(){var s = docume
export const placeAd = (() => { export const placeAd = (() => {
const feature = config.features.adsBanner; const feature = config.features.adsBanner;
if (!feature.isEnabled || feature.provider !== 'adbutler') { if (!('adButler' in feature)) {
return; return;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment