diff --git a/.github/workflows/build-android-e2e.yml b/.github/workflows/build-android-e2e.yml index dfb127783a5..bd6158501d1 100644 --- a/.github/workflows/build-android-e2e.yml +++ b/.github/workflows/build-android-e2e.yml @@ -560,7 +560,6 @@ jobs: GOOGLE_SERVICES_B64_IOS: ${{ secrets.GOOGLE_SERVICES_B64_IOS }} GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }} MM_INFURA_PROJECT_ID: ${{ secrets.MM_INFURA_PROJECT_ID }} - MM_PREDICT_GTM_MODAL_ENABLED: 'false' - name: Record Namespace E2E APK cache marker if: ${{ inputs.runner_provider == 'namespace' && steps.gate.outputs.needs-native-build == 'true' && inputs.source-fingerprint != '' && inputs.include_arm64 == false }} diff --git a/.github/workflows/build-ios-e2e.yml b/.github/workflows/build-ios-e2e.yml index f4b0c553e3a..f4501937c87 100644 --- a/.github/workflows/build-ios-e2e.yml +++ b/.github/workflows/build-ios-e2e.yml @@ -80,7 +80,6 @@ jobs: GOOGLE_SERVICES_B64_IOS: ${{ secrets.GOOGLE_SERVICES_B64_IOS }} GOOGLE_SERVICES_B64_ANDROID: ${{ secrets.GOOGLE_SERVICES_B64_ANDROID }} MM_INFURA_PROJECT_ID: ${{ secrets.MM_INFURA_PROJECT_ID }} - MM_PREDICT_GTM_MODAL_ENABLED: 'false' steps: # Get the source code from the repository diff --git a/app/components/UI/Card/Views/CardWelcome/CardWelcome.test.tsx b/app/components/UI/Card/Views/CardWelcome/CardWelcome.test.tsx index b484e6d0d06..f06cb054c6a 100644 --- a/app/components/UI/Card/Views/CardWelcome/CardWelcome.test.tsx +++ b/app/components/UI/Card/Views/CardWelcome/CardWelcome.test.tsx @@ -76,7 +76,6 @@ jest.mock('../../../../../../locales/i18n', () => ({ 'card.card_onboarding.description': 'Change your spending token and network by signing in with your Crypto Life email and password.', 'card.card_onboarding.apply_now_button': 'Sign in', - 'predict.gtm_content.not_now': 'Not now', }; return map[key] || key; }, diff --git a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.styles.ts b/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.styles.ts deleted file mode 100644 index 2927e7d8645..00000000000 --- a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.styles.ts +++ /dev/null @@ -1,131 +0,0 @@ -import { Platform, StyleSheet, Dimensions } from 'react-native'; -import { colors as importedColors } from '../../../../../styles/common'; -import { Theme } from '@metamask/design-tokens'; - -// Responsive scaling utilities -const { width: screenWidth, height: screenHeight } = Dimensions.get('window'); - -// Platform-specific base dimensions -const BASE_WIDTH = 375; -const BASE_HEIGHT_IOS = 812; // iPhone X/11/12/13/14/15 Pro base -const BASE_HEIGHT_ANDROID = 736; // Common Android base - -const MIN_SCREEN_HEIGHT_FOR_SMALL_SCREEN_STYLES = 750; - -// Calculate platform-aware scaling factors -const isIOS = Platform.OS === 'ios'; -const baseHeight = isIOS ? BASE_HEIGHT_IOS : BASE_HEIGHT_ANDROID; - -const widthScale = screenWidth / BASE_WIDTH; -const heightScale = screenHeight / baseHeight; - -// Use more conservative scaling to prevent excessive padding -const scale = Math.min(widthScale, heightScale); -const conservativeScale = Math.min(scale, 1.2); // Cap scaling at 120% - -// Platform-aware responsive scaling functions -const scaleSize = (size: number) => Math.ceil(size * conservativeScale); -const scaleFont = (size: number) => Math.ceil(size * conservativeScale); - -// For vertical spacing, use percentage of available height instead of pure scaling -const scaleVertical = (size: number) => { - // Use percentage of screen height for more consistent spacing - const percentage = size / baseHeight; - return Math.ceil(screenHeight * percentage); -}; - -const scaleHorizontal = (size: number) => Math.ceil(size * widthScale); - -const createStyles = (theme: Theme) => - StyleSheet.create({ - pageContainer: { - flex: 1, - position: 'relative', - maxHeight: '100%', - width: '100%', - }, - backgroundImage: { - position: 'absolute', - top: 0, - left: 0, - right: 0, - bottom: 0, - width: screenWidth * 1.07, // 7% wider for edge coverage - height: - screenHeight * - (screenHeight < MIN_SCREEN_HEIGHT_FOR_SMALL_SCREEN_STYLES - ? 1.12 - : 1.14), // 12% taller for edge coverage - resizeMode: 'cover', - }, - contentContainer: { - flex: 1, - }, - headerContainer: { - alignItems: 'center', - paddingHorizontal: scaleHorizontal(16), - paddingVertical: scaleVertical(16), - }, - poweredByImage: { - width: scaleHorizontal(200), - height: scaleVertical(24), - marginBottom: 8, - }, - spacer: { - flex: 1, - }, - title: { - fontFamily: 'MMPoly-Regular', - fontWeight: '400', - // make it smaller on smaller screens - fontSize: - screenHeight < MIN_SCREEN_HEIGHT_FOR_SMALL_SCREEN_STYLES ? 40 : 50, - lineHeight: - screenHeight < MIN_SCREEN_HEIGHT_FOR_SMALL_SCREEN_STYLES ? 40 : 50, // 100% of font size - letterSpacing: 0, - textAlign: 'center', - paddingTop: scaleVertical( - screenHeight < MIN_SCREEN_HEIGHT_FOR_SMALL_SCREEN_STYLES ? 8 : 12, - ), - color: theme.colors.accent02.light, - }, - titleDescription: { - // make it smaller on smaller screens - fontSize: - screenHeight < MIN_SCREEN_HEIGHT_FOR_SMALL_SCREEN_STYLES ? 14 : 16, - paddingTop: scaleVertical(10), - paddingHorizontal: scaleHorizontal(8), - textAlign: 'center', - fontFamily: Platform.OS === 'ios' ? 'System' : 'Roboto', // Default system font - fontWeight: '500', - lineHeight: 24, // Line Height BodyMd - letterSpacing: 0, - color: theme.colors.accent02.light, - }, - footerContainer: { - display: 'flex', - rowGap: scaleVertical(8), - paddingHorizontal: scaleHorizontal(30), - }, - getStartedButton: { - borderRadius: scaleSize(12), - backgroundColor: importedColors.white, - }, - getStartedButtonText: { - color: importedColors.btnBlack, - fontWeight: '600', - fontSize: scaleFont(16), - }, - notNowButton: { - borderRadius: scaleSize(12), - backgroundColor: importedColors.transparent, - borderWidth: 0, - }, - notNowButtonText: { - color: importedColors.white, - fontWeight: '500', - fontSize: scaleFont(16), - }, - }); - -export default createStyles; diff --git a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.test.tsx b/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.test.tsx deleted file mode 100644 index 6bb877f8785..00000000000 --- a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.test.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import React from 'react'; -import { fireEvent, waitFor } from '@testing-library/react-native'; -import PredictGTMModal from './PredictGTMModal'; -import StorageWrapper from '../../../../../store/storage-wrapper'; -import Routes from '../../../../../constants/navigation/Routes'; -import { MetaMetricsEvents } from '../../../../../core/Analytics'; -import { PREDICT_GTM_MODAL_SHOWN } from '../../../../../constants/storage'; -import renderWithProvider from '../../../../../util/test/renderWithProvider'; -import { backgroundState } from '../../../../../util/test/initial-root-state'; -import { useAnalytics } from '../../../../../components/hooks/useAnalytics/useAnalytics'; -import { createMockUseAnalyticsHook } from '../../../../../util/test/analyticsMock'; - -jest.mock('../../../../../util/theme', () => { - const { mockTheme } = jest.requireActual('../../../../../util/theme'); - return { - useTheme: jest.fn(() => mockTheme), - }; -}); - -jest.mock('../../../../../../locales/i18n', () => ({ - strings: (key: string) => key, -})); - -jest.mock('../../../../../store/storage-wrapper', () => ({ - getItem: jest.fn(), - setItem: jest.fn(), -})); - -const mockNavigate = jest.fn(); -jest.mock('@react-navigation/native', () => { - const actualNav = jest.requireActual('@react-navigation/native'); - return { - ...actualNav, - useNavigation: () => ({ - navigate: mockNavigate, - goBack: jest.fn(), - }), - }; -}); - -const mockTrackEvent = jest.fn(); -const mockCreateEventBuilder = jest.fn().mockReturnValue({ - addProperties: jest.fn().mockReturnThis(), - build: jest.fn().mockReturnValue({}), -}); -jest.mock('../../../../../components/hooks/useAnalytics/useAnalytics'); - -jest.mock('../../../../../util/metrics', () => ({ - __esModule: true, - default: jest.fn(() => ({ - platform: 'ios', - deviceModel: 'iPhone 14', - })), -})); - -const initialState = { - engine: { - backgroundState, - }, -}; - -describe('PredictGTMModal', () => { - beforeEach(() => { - jest.clearAllMocks(); - jest.mocked(useAnalytics).mockReturnValue( - createMockUseAnalyticsHook({ - trackEvent: mockTrackEvent, - createEventBuilder: mockCreateEventBuilder, - }), - ); - jest.mocked(StorageWrapper.getItem).mockResolvedValue('false'); - }); - - it('renders correctly with all main elements', async () => { - const { getByText, getByTestId } = renderWithProvider(, { - state: initialState, - }); - - await waitFor(() => { - expect(getByText('predict.gtm_content.title')).toBeTruthy(); - expect(getByText('predict.gtm_content.title_description')).toBeTruthy(); - expect(getByText('predict.gtm_content.get_started')).toBeTruthy(); - expect(getByText('predict.gtm_content.not_now')).toBeTruthy(); - expect(getByTestId('predict-gtm-modal-container')).toBeTruthy(); - }); - }); - - it('handles close button press correctly', async () => { - const { getByText } = renderWithProvider(, { - state: initialState, - }); - - await waitFor(() => { - const notNowButton = getByText('predict.gtm_content.not_now'); - fireEvent.press(notNowButton); - }); - - expect(StorageWrapper.setItem).toHaveBeenCalledWith( - PREDICT_GTM_MODAL_SHOWN, - 'true', - ); - expect(mockTrackEvent).toHaveBeenCalled(); - expect(mockCreateEventBuilder).toHaveBeenCalledWith( - MetaMetricsEvents.WHATS_NEW_LINK_CLICKED, - ); - expect(mockNavigate).toHaveBeenCalledWith(Routes.WALLET.HOME); - }); - - it('handles get started button press correctly', async () => { - const { getByText } = renderWithProvider(, { - state: initialState, - }); - - await waitFor(() => { - const getStartedButton = getByText('predict.gtm_content.get_started'); - fireEvent.press(getStartedButton); - }); - - expect(StorageWrapper.setItem).toHaveBeenCalledWith( - PREDICT_GTM_MODAL_SHOWN, - 'true', - { emitEvent: false }, - ); - expect(mockTrackEvent).toHaveBeenCalled(); - expect(mockCreateEventBuilder).toHaveBeenCalledWith( - MetaMetricsEvents.WHATS_NEW_LINK_CLICKED, - ); - expect(mockNavigate).toHaveBeenCalledWith(Routes.WALLET.HOME); - expect(mockNavigate).toHaveBeenCalledWith(Routes.PREDICT.ROOT, { - screen: Routes.PREDICT.MARKET_LIST, - params: { - entryPoint: expect.any(String), - }, - }); - }); - - it('renders image correctly', async () => { - const { getByTestId } = renderWithProvider(, { - state: initialState, - }); - - await waitFor(() => { - expect(getByTestId('predict-gtm-modal-container')).toBeTruthy(); - }); - }); -}); diff --git a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.testIds.ts b/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.testIds.ts deleted file mode 100644 index daf34be298f..00000000000 --- a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.testIds.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const PREDICT_GTM_MODAL_TEST_IDS = { - CONTAINER: 'predict-gtm-modal-container', - GET_STARTED_BUTTON: 'predict-gtm-get-started-button', - NOT_NOW_BUTTON: 'predict-gtm-not-now-button', -} as const; diff --git a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.tsx b/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.tsx deleted file mode 100644 index fe31f0e12aa..00000000000 --- a/app/components/UI/Predict/components/PredictGTMModal/PredictGTMModal.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import { useNavigation } from '@react-navigation/native'; -import React, { useState, useEffect } from 'react'; -import { Image, View } from 'react-native'; -import Animated, { - useSharedValue, - useAnimatedStyle, - withTiming, -} from 'react-native-reanimated'; -import { SafeAreaView } from 'react-native-safe-area-context'; -import { strings } from '../../../../../../locales/i18n'; -import ButtonBase from '../../../../../component-library/components/Buttons/Button/foundation/ButtonBase'; -import Button, { - ButtonSize, - ButtonVariants, - ButtonWidthTypes, -} from '../../../../../component-library/components/Buttons/Button'; -import Text, { - TextVariant, -} from '../../../../../component-library/components/Texts/Text'; -import { useAnalytics } from '../../../../../components/hooks/useAnalytics/useAnalytics'; -import Routes from '../../../../../constants/navigation/Routes'; -import { MetaMetricsEvents } from '../../../../../core/Analytics'; -import PredictMarketingImage from '../../../../../images/predict-marketing.png'; -import PoweredByPolymarketImage from '../../../../../images/powered-by-polymarket.png'; -import StorageWrapper from '../../../../../store/storage-wrapper'; -import { PREDICT_GTM_MODAL_SHOWN } from '../../../../../constants/storage'; -import { useTheme } from '../../../../../util/theme'; -import generateDeviceAnalyticsMetaData from '../../../../../util/metrics'; -import createStyles from './PredictGTMModal.styles'; -import { - PREDICT_GTM_MODAL_DECLINE, - PREDICT_GTM_MODAL_ENGAGE, - PREDICT_GTM_WHATS_NEW_MODAL, - PredictEventValues, -} from '../../constants/eventNames'; -import { PREDICT_GTM_MODAL_TEST_IDS } from './PredictGTMModal.testIds'; - -const PredictGTMModal = () => { - const { trackEvent, createEventBuilder } = useAnalytics(); - const { navigate } = useNavigation(); - const theme = useTheme(); - const [imageLoaded, setImageLoaded] = useState(false); - const opacity = useSharedValue(0); - - const titleText = strings('predict.gtm_content.title'); - const subtitleText = strings('predict.gtm_content.title_description'); - - const styles = createStyles(theme); - - // Animate content fade-in when image loads - useEffect(() => { - if (imageLoaded) { - opacity.value = withTiming(1, { duration: 500 }); - } - }, [imageLoaded, opacity]); - - const animatedStyle = useAnimatedStyle(() => ({ - opacity: opacity.value, - })); - - const handleClose = async () => { - await StorageWrapper.setItem(PREDICT_GTM_MODAL_SHOWN, 'true'); - - trackEvent( - createEventBuilder(MetaMetricsEvents.WHATS_NEW_LINK_CLICKED) - .addProperties({ - ...generateDeviceAnalyticsMetaData(), - feature: PREDICT_GTM_WHATS_NEW_MODAL, - action: PREDICT_GTM_MODAL_DECLINE, - }) - .build(), - ); - - navigate(Routes.WALLET.HOME); - }; - - const handleGetStarted = async () => { - trackEvent( - createEventBuilder(MetaMetricsEvents.WHATS_NEW_LINK_CLICKED) - .addProperties({ - ...generateDeviceAnalyticsMetaData(), - feature: PREDICT_GTM_WHATS_NEW_MODAL, - action: PREDICT_GTM_MODAL_ENGAGE, - }) - .build(), - ); - - await StorageWrapper.setItem(PREDICT_GTM_MODAL_SHOWN, 'true', { - emitEvent: false, - }); - - navigate(Routes.WALLET.HOME); - - navigate(Routes.PREDICT.ROOT, { - screen: Routes.PREDICT.MARKET_LIST, - params: { - entryPoint: PredictEventValues.ENTRY_POINT.GTM_MODAL, - }, - }); - }; - - return ( - - {/* Background Image - Full Screen */} - setImageLoaded(true)} - /> - - {/* Content Overlay */} - - {/* Header Section */} - - - - {titleText} - - - {subtitleText} - - - - {/* Spacer to push footer to bottom */} - - - {/* Footer Section */} - - handleGetStarted()} - testID={PREDICT_GTM_MODAL_TEST_IDS.GET_STARTED_BUTTON} - size={ButtonSize.Lg} - width={ButtonWidthTypes.Full} - style={styles.getStartedButton} - activeOpacity={0.6} - label={ - - {strings('predict.gtm_content.get_started')} - - } - /> -