diff --git a/.env.dist b/.env.dist index 5fe2b69a1..9f638536d 100644 --- a/.env.dist +++ b/.env.dist @@ -23,3 +23,5 @@ DYNAMIC_LINKS_DOMAIN_URI_PREFIX=https://templenft.page.link HYPELAB_AD_FRAME_URL= HYPELAB_SMALL_PLACEMENT_SLUG= HYPELAB_NATIVE_PLACEMENT_SLUG= + +PERSONA_PLACEMENT_SLUG= diff --git a/.github/workflows/apk-build.yml b/.github/workflows/apk-build.yml index d86aed7f4..eb9ab785e 100644 --- a/.github/workflows/apk-build.yml +++ b/.github/workflows/apk-build.yml @@ -51,6 +51,7 @@ jobs: HYPELAB_AD_FRAME_URL: ${{ vars.HYPELAB_AD_FRAME_URL }} HYPELAB_SMALL_PLACEMENT_SLUG: ${{ vars.HYPELAB_SMALL_PLACEMENT_SLUG }} HYPELAB_NATIVE_PLACEMENT_SLUG: ${{ vars.HYPELAB_NATIVE_PLACEMENT_SLUG }} + PERSONA_PLACEMENT_SLUG: ${{ vars.PERSONA_PLACEMENT_SLUG }} APPSTORE_AUTHKEY: ${{ secrets.APPSTORE_AUTHKEY }} GOOGLE_PLAY_AUTHKEY: ${{ secrets.GOOGLE_PLAY_AUTHKEY }} KEYSTORE_KEY: ${{ secrets.KEYSTORE_KEY }} diff --git a/.github/workflows/fastlane-build.yml b/.github/workflows/fastlane-build.yml index 1d4bb1e05..3f0c70f2f 100644 --- a/.github/workflows/fastlane-build.yml +++ b/.github/workflows/fastlane-build.yml @@ -47,6 +47,7 @@ jobs: HYPELAB_AD_FRAME_URL: ${{ vars.HYPELAB_AD_FRAME_URL }} HYPELAB_SMALL_PLACEMENT_SLUG: ${{ vars.HYPELAB_SMALL_PLACEMENT_SLUG }} HYPELAB_NATIVE_PLACEMENT_SLUG: ${{ vars.HYPELAB_NATIVE_PLACEMENT_SLUG }} + PERSONA_PLACEMENT_SLUG: ${{ vars.PERSONA_PLACEMENT_SLUG }} APPSTORE_AUTHKEY: ${{ secrets.APPSTORE_AUTHKEY }} GOOGLE_PLAY_AUTHKEY: ${{ secrets.GOOGLE_PLAY_AUTHKEY }} KEYSTORE_KEY: ${{ secrets.KEYSTORE_KEY }} diff --git a/.github/workflows/secrets-setup/action.yml b/.github/workflows/secrets-setup/action.yml index 4139c94b1..52698d87c 100644 --- a/.github/workflows/secrets-setup/action.yml +++ b/.github/workflows/secrets-setup/action.yml @@ -32,6 +32,7 @@ runs: HYPELAB_AD_FRAME_URL=${{ inputs.HYPELAB_AD_FRAME_URL }} HYPELAB_SMALL_PLACEMENT_SLUG=${{ inputs.HYPELAB_SMALL_PLACEMENT_SLUG }} HYPELAB_NATIVE_PLACEMENT_SLUG=${{ inputs.HYPELAB_NATIVE_PLACEMENT_SLUG }} + PERSONA_PLACEMENT_SLUG=${{ inputs.PERSONA_PLACEMENT_SLUG }} APK_BUILD_ID=${{ inputs.APK_BUILD_ID }} EOF diff --git a/.github/workflows/testapp-build.yml b/.github/workflows/testapp-build.yml index 1d99cbc8c..abce79220 100644 --- a/.github/workflows/testapp-build.yml +++ b/.github/workflows/testapp-build.yml @@ -57,6 +57,7 @@ jobs: HYPELAB_AD_FRAME_URL: ${{ vars.HYPELAB_AD_FRAME_URL }} HYPELAB_SMALL_PLACEMENT_SLUG: ${{ vars.HYPELAB_SMALL_PLACEMENT_SLUG }} HYPELAB_NATIVE_PLACEMENT_SLUG: ${{ vars.HYPELAB_NATIVE_PLACEMENT_SLUG }} + PERSONA_PLACEMENT_SLUG: ${{ vars.PERSONA_PLACEMENT_SLUG }} APPSTORE_AUTHKEY: ${{ secrets.APPSTORE_AUTHKEY }} GOOGLE_PLAY_AUTHKEY: ${{ secrets.GOOGLE_PLAY_AUTHKEY }} KEYSTORE_KEY: ${{ secrets.KEYSTORE_KEY }} diff --git a/src/components/hypelab-promotion/index.tsx b/src/components/hypelab-promotion/index.tsx index 72e270031..ffb594af0 100644 --- a/src/components/hypelab-promotion/index.tsx +++ b/src/components/hypelab-promotion/index.tsx @@ -1,176 +1,36 @@ -import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { LayoutChangeEvent, LayoutRectangle, View } from 'react-native'; -import { WebView, WebViewMessageEvent } from 'react-native-webview'; +import React, { memo } from 'react'; -import { Icon } from 'src/components/icon/icon'; -import { IconNameEnum } from 'src/components/icon/icon-name.enum'; -import { ImagePromotionView } from 'src/components/image-promotion-view'; -import { TextPromotionItemSelectors } from 'src/components/text-promotion-view/selectors'; -import { TouchableWithAnalytics } from 'src/components/touchable-with-analytics'; -import { layoutScale } from 'src/config/styles'; -import { AdFrameMessageType } from 'src/enums/ad-frame-message-type.enum'; +import { PromotionProviderEnum } from 'src/enums/promotion-provider.enum'; import { PromotionVariantEnum } from 'src/enums/promotion-variant.enum'; -import { ThemesEnum } from 'src/interfaces/theme.enum'; -import { useThemeSelector } from 'src/store/settings/settings-selectors'; -import { formatSize } from 'src/styles/format-size'; -import { useColors } from 'src/styles/use-colors'; -import { AdFrameMessage, SingleProviderPromotionProps } from 'src/types/promotion'; -import { AnalyticsEventCategory } from 'src/utils/analytics/analytics-event.enum'; -import { useAnalytics } from 'src/utils/analytics/use-analytics.hook'; -import { HYPELAB_AD_FRAME_URL, HYPELAB_NATIVE_PLACEMENT_SLUG, HYPELAB_SMALL_PLACEMENT_SLUG } from 'src/utils/env.utils'; -import { useTimeout } from 'src/utils/hooks'; +import { SingleProviderPromotionProps } from 'src/types/promotion'; +import { HYPELAB_NATIVE_PLACEMENT_SLUG, HYPELAB_SMALL_PLACEMENT_SLUG } from 'src/utils/env.utils'; import { isDefined } from 'src/utils/is-defined'; -import { isString } from 'src/utils/is-string'; -import { openUrl } from 'src/utils/linking'; -import { useHypelabPromotionStyles } from './styles'; +import { WebViewPromotion } from '../webview-promotion'; const AD_CONTENT_RELATED_URL_SEARCH_PARAMS = ['campaign_slug', 'creative_set_slug', 'placement_slug']; -export const HypelabPromotion = memo( - ({ variant, isVisible, shouldShowCloseButton, onClose, onReady, onError, ...testIDProps }) => { - const { testID, testIDProperties } = testIDProps; - const isImageAd = variant === PromotionVariantEnum.Image; - const colors = useColors(); - const styles = useHypelabPromotionStyles(); - const theme = useThemeSelector(); - const { trackEvent } = useAnalytics(); - const [adHref, setAdHref] = useState(); - const adHrefRef = useRef(adHref); - - useEffect(() => void (adHrefRef.current = adHref), [adHref]); - - const [layoutRect, setLayoutRect] = useState(); - const initialSize = useMemo(() => { - if (isImageAd) { - return { w: 320, h: 50 }; - } - - return layoutRect ? { w: Math.round(layoutRect.width / layoutScale), h: 80 } : undefined; - }, [isImageAd, layoutRect]); - const [size, setSize] = useState(initialSize); - useEffect(() => void (initialSize && setSize(prevSize => prevSize ?? initialSize)), [initialSize]); - - const adFrameSource = useMemo(() => { - const placementSlug = isImageAd ? HYPELAB_SMALL_PLACEMENT_SLUG : HYPELAB_NATIVE_PLACEMENT_SLUG; - const origin = theme === ThemesEnum.dark ? 'mobile-dark' : 'mobile-light'; - - if (!initialSize) { - return undefined; - } - - const searchParams = new URLSearchParams({ - p: placementSlug, - o: origin, - vw: formatSize(Number(initialSize.w)).toString(), - w: Number(initialSize.w).toString(), - h: Number(initialSize.h).toString() - }); - - return { uri: `${HYPELAB_AD_FRAME_URL}/?${searchParams.toString()}` }; - }, [isImageAd, initialSize, theme]); - - const handleMainLayout = useCallback((e: LayoutChangeEvent) => { - e.persist(); - setLayoutRect(e.nativeEvent.layout); - }, []); - - useTimeout( - () => { - if (!isString(adHrefRef.current)) { - onError(); - } - }, - 30000, - [onError] - ); - - const handleAdFrameMessage = useCallback( - (e: WebViewMessageEvent) => { - try { - const message: AdFrameMessage = JSON.parse(e.nativeEvent.data); - - switch (message.type) { - case AdFrameMessageType.Resize: - if (message.height !== 0 && message.width !== 0) { - setSize({ w: Math.round(message.width / layoutScale), h: Math.round(message.height / layoutScale) }); - } - break; - case AdFrameMessageType.Ready: - const prevAdHrefSearchParams = isDefined(adHref) ? new URL(adHref).searchParams : new URLSearchParams(); - const newAdHrefSearchParams = new URL(message.ad.cta_url).searchParams; - setAdHref(message.ad.cta_url); - if ( - AD_CONTENT_RELATED_URL_SEARCH_PARAMS.some( - paramName => prevAdHrefSearchParams.get(paramName) !== newAdHrefSearchParams.get(paramName) - ) - ) { - onReady(); - } - break; - case AdFrameMessageType.Error: - onError(); - break; - case AdFrameMessageType.Click: - if (isString(adHref)) { - trackEvent(testID, AnalyticsEventCategory.ButtonPress, testIDProperties); - openUrl(adHref); - } - } - } catch (err) { - console.error(err); - } - }, - [adHref, onError, onReady, testID, testIDProperties, trackEvent] - ); - - const webViewCommonProps = { - allowsInlineMediaPlayback: true, - source: adFrameSource, - onError: onError, - onMessage: handleAdFrameMessage, - webviewDebuggingEnabled: __DEV__, - scrollEnabled: false, - scalesPageToFit: false, - textZoom: 100 - }; - - if (isImageAd) { - return ( - - - - - - ); - } - - return ( - - {adFrameSource && size && ( - - )} - {shouldShowCloseButton && ( - - - - )} - - ); - } -); +const adChanged = (prevUrl: string | undefined, newUrl: string) => { + const prevAdHrefSearchParams = isDefined(prevUrl) ? new URL(prevUrl).searchParams : new URLSearchParams(); + const newAdHrefSearchParams = new URL(newUrl).searchParams; + + return AD_CONTENT_RELATED_URL_SEARCH_PARAMS.some( + paramName => prevAdHrefSearchParams.get(paramName) !== newAdHrefSearchParams.get(paramName) + ); +}; + +export const HypelabPromotion = memo(({ variant, ...restProps }) => { + const isImageAd = variant === PromotionVariantEnum.Image; + + return ( + + ); +}); diff --git a/src/components/persona-promotion/index.tsx b/src/components/persona-promotion/index.tsx new file mode 100644 index 000000000..00c5e0856 --- /dev/null +++ b/src/components/persona-promotion/index.tsx @@ -0,0 +1,27 @@ +import React, { memo } from 'react'; + +import { WebViewPromotion } from 'src/components/webview-promotion'; +import { PromotionProviderEnum } from 'src/enums/promotion-provider.enum'; +import { PromotionVariantEnum } from 'src/enums/promotion-variant.enum'; +import { SingleProviderPromotionProps } from 'src/types/promotion'; +import { PERSONA_PLACEMENT_SLUG } from 'src/utils/env.utils'; + +const adChanged = () => true; + +export const PersonaPromotion = memo(({ variant, ...restProps }) => { + if (variant === PromotionVariantEnum.Text) { + return null; + } + + return ( + + ); +}); diff --git a/src/components/promotion-item/index.tsx b/src/components/promotion-item/index.tsx index ea0cb7739..8802030d2 100644 --- a/src/components/promotion-item/index.tsx +++ b/src/components/promotion-item/index.tsx @@ -5,6 +5,7 @@ import { StyleProp, View, ViewProps, ViewStyle } from 'react-native'; import { ActivityIndicator } from 'src/components/activity-indicator'; import { HypelabPromotion } from 'src/components/hypelab-promotion'; import { OptimalPromotion } from 'src/components/optimal-promotion'; +import { PersonaPromotion } from 'src/components/persona-promotion'; import { PROMO_SYNC_INTERVAL } from 'src/config/fixed-times'; import { isAndroid } from 'src/config/system'; import { PromotionProviderEnum } from 'src/enums/promotion-provider.enum'; @@ -21,7 +22,7 @@ interface Props { style?: StyleProp; shouldRefreshAd?: boolean; shouldShowCloseButton?: boolean; - shouldTryHypelabAd?: boolean; + onlyOptimalAd?: boolean; variant?: PromotionVariantEnum; testID: string; pageName: string; @@ -37,9 +38,9 @@ export const PromotionItem = forwardRef( style, shouldRefreshAd = false, shouldShowCloseButton = true, - variant = PromotionVariantEnum.Image, - shouldTryHypelabAd = true, testID, + variant = PromotionVariantEnum.Image, + onlyOptimalAd = false, pageName, onError, onLoad, @@ -94,12 +95,19 @@ export const PromotionItem = forwardRef( }, [onError]); const handleOptimalError = useCallback(() => { - if (!shouldTryHypelabAd) { + if (onlyOptimalAd) { handleAdError(); + } else { + setAdsState(prevState => ({ ...prevState, currentProvider: PromotionProviderEnum.HypeLab })); } - setAdsState(prevState => ({ ...prevState, currentProvider: PromotionProviderEnum.HypeLab })); - }, [handleAdError, shouldTryHypelabAd]); - const handleHypelabError = useCallback(() => handleAdError(), [handleAdError]); + }, [handleAdError, onlyOptimalAd]); + const handleHypelabError = useCallback(() => { + if (variant === PromotionVariantEnum.Text) { + handleAdError(); + } else { + setAdsState(prevState => ({ ...prevState, currentProvider: PromotionProviderEnum.Persona })); + } + }, [handleAdError, variant]); const handleAdReadyFactory = useCallback( (provider: PromotionProviderEnum) => () => { @@ -116,6 +124,10 @@ export const PromotionItem = forwardRef( () => handleAdReadyFactory(PromotionProviderEnum.HypeLab), [handleAdReadyFactory] ); + const handlePersonaAdReady = useMemo( + () => handleAdReadyFactory(PromotionProviderEnum.Persona), + [handleAdReadyFactory] + ); const testIDProperties = useMemo( () => ({ @@ -131,6 +143,15 @@ export const PromotionItem = forwardRef( return null; } + const promotionCommonProps = { + testID, + testIDProperties, + variant, + isVisible: adIsReady, + shouldShowCloseButton, + onClose: hidePromotion + }; + return ( ( > {currentProvider === PromotionProviderEnum.Optimal && isFocused && ( )} - {currentProvider === PromotionProviderEnum.HypeLab && shouldTryHypelabAd && isFocused && ( - + {currentProvider === PromotionProviderEnum.HypeLab && isFocused && ( + + )} + {currentProvider === PromotionProviderEnum.Persona && isFocused && ( + )} {!adIsReady && ( diff --git a/src/components/webview-promotion/index.tsx b/src/components/webview-promotion/index.tsx new file mode 100644 index 000000000..9e459a5eb --- /dev/null +++ b/src/components/webview-promotion/index.tsx @@ -0,0 +1,211 @@ +import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { LayoutChangeEvent, LayoutRectangle, View } from 'react-native'; +import { WebView, WebViewMessageEvent } from 'react-native-webview'; + +import { layoutScale } from 'src/config/styles'; +import { AdFrameMessageType } from 'src/enums/ad-frame-message-type.enum'; +import { PromotionProviderEnum } from 'src/enums/promotion-provider.enum'; +import { PromotionVariantEnum } from 'src/enums/promotion-variant.enum'; +import { ThemesEnum } from 'src/interfaces/theme.enum'; +import { useThemeSelector } from 'src/store/settings/settings-selectors'; +import { useCurrentAccountPkhSelector } from 'src/store/wallet/wallet-selectors'; +import { formatSize } from 'src/styles/format-size'; +import { useColors } from 'src/styles/use-colors'; +import { AdFrameMessage, SingleProviderPromotionProps } from 'src/types/promotion'; +import { AnalyticsEventCategory } from 'src/utils/analytics/analytics-event.enum'; +import { useAnalytics } from 'src/utils/analytics/use-analytics.hook'; +import { HYPELAB_AD_FRAME_URL } from 'src/utils/env.utils'; +import { useTimeout } from 'src/utils/hooks'; +import { isDefined } from 'src/utils/is-defined'; +import { isString } from 'src/utils/is-string'; +import { openUrl } from 'src/utils/linking'; + +import { Icon } from '../icon/icon'; +import { IconNameEnum } from '../icon/icon-name.enum'; +import { ImagePromotionView } from '../image-promotion-view'; +import { TextPromotionItemSelectors } from '../text-promotion-view/selectors'; +import { TouchableWithAnalytics } from '../touchable-with-analytics'; + +import { WebviewPromotionStyles } from './styles'; + +interface WebViewPromotionProps extends SingleProviderPromotionProps { + provider: PromotionProviderEnum.HypeLab | PromotionProviderEnum.Persona; + placementSlug: string; + initialOriginalWidth?: number; + initialOriginalHeight?: number; + adChanged: (prevUrl: string | undefined, newUrl: string) => boolean; +} + +export const WebViewPromotion = memo( + ({ + variant, + isVisible, + shouldShowCloseButton, + provider, + initialOriginalWidth, + initialOriginalHeight, + placementSlug, + adChanged, + onClose, + onReady, + onError, + ...testIDProps + }) => { + const { testID, testIDProperties } = testIDProps; + const isImageAd = variant === PromotionVariantEnum.Image; + const accountPkh = useCurrentAccountPkhSelector(); + const colors = useColors(); + const theme = useThemeSelector(); + const { trackEvent } = useAnalytics(); + const [adHref, setAdHref] = useState(); + + const adHrefRef = useRef(adHref); + useEffect(() => void (adHrefRef.current = adHref), [adHref]); + + const [layoutRect, setLayoutRect] = useState(); + const initialSize = useMemo(() => { + if (isDefined(initialOriginalWidth) && isDefined(initialOriginalHeight)) { + return { w: initialOriginalWidth, h: initialOriginalHeight }; + } + + return layoutRect + ? { + w: initialOriginalWidth ?? Math.round(layoutRect.width / layoutScale), + h: initialOriginalHeight ?? Math.round(layoutRect.height / layoutScale) + } + : undefined; + }, [initialOriginalHeight, initialOriginalWidth, layoutRect]); + const [size, setSize] = useState(initialSize); + useEffect(() => void (initialSize && setSize(prevSize => prevSize ?? initialSize)), [initialSize]); + + const adFrameSource = useMemo(() => { + const origin = theme === ThemesEnum.dark ? 'mobile-dark' : 'mobile-light'; + + if (!initialSize) { + return undefined; + } + + const searchParams = new URLSearchParams({ + p: placementSlug, + o: origin, + vw: formatSize(Number(initialSize.w)).toString(), + vh: formatSize(Number(initialSize.h)).toString(), + w: initialSize.w.toString(), + h: initialSize.h.toString(), + ap: provider.toLowerCase() + }); + if (provider === PromotionProviderEnum.Persona) { + searchParams.set('a', accountPkh); + } + + return { uri: `${HYPELAB_AD_FRAME_URL}/?${searchParams.toString()}` }; + }, [theme, initialSize, placementSlug, provider, accountPkh]); + + const handleContainerLayout = useCallback((e: LayoutChangeEvent) => { + e.persist(); + setLayoutRect(e.nativeEvent.layout); + }, []); + + useTimeout(() => void (!isString(adHrefRef.current) && onError()), 30000, [onError]); + + const handleAdFrameMessage = useCallback( + (e: WebViewMessageEvent) => { + try { + const message: AdFrameMessage = JSON.parse(e.nativeEvent.data); + + switch (message.type) { + case AdFrameMessageType.Resize: + if (message.height !== 0 && message.width !== 0) { + setSize({ w: Math.round(message.width / layoutScale), h: Math.round(message.height / layoutScale) }); + } + break; + case AdFrameMessageType.Ready: + setAdHref(message.ad.cta_url); + if (adChanged(adHref, message.ad.cta_url)) { + onReady(); + } + break; + case AdFrameMessageType.Error: + onError(); + break; + case AdFrameMessageType.Click: + if (isString(adHref)) { + trackEvent(testID, AnalyticsEventCategory.ButtonPress, testIDProperties); + openUrl(adHref); + } + } + } catch (err) { + console.error(err); + } + }, + [adHref, onError, onReady, testID, testIDProperties, trackEvent, adChanged] + ); + + const webViewCommonProps = useMemo( + () => ({ + allowsInlineMediaPlayback: true, + source: adFrameSource, + onError, + onMessage: handleAdFrameMessage, + webviewDebuggingEnabled: __DEV__, + scrollEnabled: false, + scalesPageToFit: false, + textZoom: 100 + }), + [adFrameSource, handleAdFrameMessage, onError] + ); + + if (isImageAd) { + return ( + + + {adFrameSource && ( + + )} + + + ); + } + + return ( + + {adFrameSource && size && ( + + )} + {shouldShowCloseButton && ( + + + + )} + + ); + } +); diff --git a/src/components/hypelab-promotion/styles.ts b/src/components/webview-promotion/styles.ts similarity index 75% rename from src/components/hypelab-promotion/styles.ts rename to src/components/webview-promotion/styles.ts index 4478b6a32..e22e5a6a3 100644 --- a/src/components/hypelab-promotion/styles.ts +++ b/src/components/webview-promotion/styles.ts @@ -1,10 +1,9 @@ -import { createUseStylesMemoized } from 'src/styles/create-use-styles'; +import { StyleSheet } from 'react-native'; + import { formatSize } from 'src/styles/format-size'; -export const useHypelabPromotionStyles = createUseStylesMemoized(() => ({ +export const WebviewPromotionStyles = StyleSheet.create({ imageAdFrameWrapper: { - width: formatSize(320), - height: formatSize(50), borderRadius: formatSize(8) }, imageAdFrame: { @@ -32,4 +31,4 @@ export const useHypelabPromotionStyles = createUseStylesMemoized(() => ({ webView: { opacity: 0.99 } -})); +}); diff --git a/src/enums/promotion-provider.enum.ts b/src/enums/promotion-provider.enum.ts index 07a5c0c42..28017f032 100644 --- a/src/enums/promotion-provider.enum.ts +++ b/src/enums/promotion-provider.enum.ts @@ -1,4 +1,5 @@ export enum PromotionProviderEnum { Optimal = 'Optimal', - HypeLab = 'HypeLab' + HypeLab = 'HypeLab', + Persona = 'Persona' } diff --git a/src/hooks/use-outside-of-list-intersection.hook.ts b/src/hooks/use-outside-of-list-intersection.hook.ts index eb294a4e7..576b990b1 100644 --- a/src/hooks/use-outside-of-list-intersection.hook.ts +++ b/src/hooks/use-outside-of-list-intersection.hook.ts @@ -44,7 +44,7 @@ export const useOutsideOfListIntersection = ( }; if (element && !parentRef) { - element.measureInWindow((x, y, width, height) => { + element.measure((x, y, width, height) => { handleNewDimensions(Dimensions.get('window'), { x, y, width, height }); }); diff --git a/src/screens/d-apps/promotion-carousel/promotion-carousel.tsx b/src/screens/d-apps/promotion-carousel/promotion-carousel.tsx index 74ec63c07..2b3724c51 100644 --- a/src/screens/d-apps/promotion-carousel/promotion-carousel.tsx +++ b/src/screens/d-apps/promotion-carousel/promotion-carousel.tsx @@ -51,7 +51,7 @@ export const PromotionCarousel = () => { pageName={adPageName} shouldShowCloseButton={false} style={styles.promotionItem} - shouldTryHypelabAd={false} + onlyOptimalAd onError={() => setPromotionErrorOccurred(true)} onLoad={onAdLoad} /> diff --git a/src/types/promotion.ts b/src/types/promotion.ts index b475e2950..7ff31d553 100644 --- a/src/types/promotion.ts +++ b/src/types/promotion.ts @@ -26,8 +26,13 @@ interface ReadyAdMessage extends AdFrameMessageBase { ad: { cta_url: string }; } -interface OtherAdMessage extends AdFrameMessageBase { - type: Exclude; +interface ErrorAdMessage extends AdFrameMessageBase { + type: AdFrameMessageType.Error; + reason?: string; } -export type AdFrameMessage = ResizeAdMessage | ReadyAdMessage | OtherAdMessage; +interface ClickAdMessage extends AdFrameMessageBase { + type: AdFrameMessageType.Click; +} + +export type AdFrameMessage = ResizeAdMessage | ReadyAdMessage | ErrorAdMessage | ClickAdMessage; diff --git a/src/utils/env.utils.ts b/src/utils/env.utils.ts index 5b7281e2f..09c992f65 100644 --- a/src/utils/env.utils.ts +++ b/src/utils/env.utils.ts @@ -34,3 +34,5 @@ export const APK_BUILD_ID = getEnv('APK_BUILD_ID'); export const HYPELAB_AD_FRAME_URL = getEnv('HYPELAB_AD_FRAME_URL'); export const HYPELAB_SMALL_PLACEMENT_SLUG = getEnv('HYPELAB_SMALL_PLACEMENT_SLUG'); export const HYPELAB_NATIVE_PLACEMENT_SLUG = getEnv('HYPELAB_NATIVE_PLACEMENT_SLUG'); + +export const PERSONA_PLACEMENT_SLUG = getEnv('PERSONA_PLACEMENT_SLUG');