diff --git a/src/components/FeatureTrainingModal.tsx b/src/components/FeatureTrainingModal.tsx index 5c9263e911b0..32c86a0af476 100644 --- a/src/components/FeatureTrainingModal.tsx +++ b/src/components/FeatureTrainingModal.tsx @@ -1,6 +1,6 @@ import type {VideoReadyForDisplayEvent} from 'expo-av'; import type {ImageContentFit} from 'expo-image'; -import React, {useCallback, useEffect, useState} from 'react'; +import React, {useCallback, useEffect, useLayoutEffect, useState} from 'react'; import {InteractionManager, View} from 'react-native'; import type {StyleProp, ViewStyle} from 'react-native'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; @@ -10,6 +10,7 @@ import useNetwork from '@hooks/useNetwork'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; +import {parseFSAttributes} from '@libs/Fullstory'; import Navigation from '@libs/Navigation/Navigation'; import variables from '@styles/variables'; import {dismissTrackTrainingModal} from '@userActions/User'; @@ -264,6 +265,14 @@ function FeatureTrainingModal({ onConfirm?.(); }, [onConfirm, closeModal]); + /** + * Extracts values from the non-scraped attribute WEB_PROP_ATTR at build time + * to ensure necessary properties are available for further processing. + * Reevaluates "fs-class" to dynamically apply styles or behavior based on + * updated attribute values. + */ + useLayoutEffect(parseFSAttributes, []); + return ( {({safeAreaPaddingBottomStyle}) => ( @@ -286,7 +295,11 @@ function FeatureTrainingModal({ ...modalInnerContainerStyle, }} > - + {renderIllustration()} diff --git a/src/components/MigratedUserWelcomeModal.tsx b/src/components/MigratedUserWelcomeModal.tsx index 312f6e0f77d0..6a1221797bda 100644 --- a/src/components/MigratedUserWelcomeModal.tsx +++ b/src/components/MigratedUserWelcomeModal.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useLayoutEffect} from 'react'; import {View} from 'react-native'; import useLocalize from '@hooks/useLocalize'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; @@ -6,6 +6,7 @@ import useStyleUtils from '@hooks/useStyleUtils'; import useThemeStyles from '@hooks/useThemeStyles'; import {dismissProductTraining} from '@libs/actions/Welcome'; import convertToLTR from '@libs/convertToLTR'; +import {parseFSAttributes} from '@libs/Fullstory'; import variables from '@styles/variables'; import CONST from '@src/CONST'; import type {FeatureListItem} from './FeatureList'; @@ -36,6 +37,14 @@ function OnboardingWelcomeVideo() { const StyleUtils = useStyleUtils(); const {shouldUseNarrowLayout} = useResponsiveLayout(); + /** + * Extracts values from the non-scraped attribute WEB_PROP_ATTR at build time + * to ensure necessary properties are available for further processing. + * Reevaluates "fs-class" to dynamically apply styles or behavior based on + * updated attribute values. + */ + useLayoutEffect(parseFSAttributes, []); + return ( - + {ExpensifyFeatures.map(({translationKey, icon}) => ( { const tooltip = TOOLTIPS[tooltipName]; return ( - + {renderTooltipContent()}; + content = ( + + {renderTooltipContent()} + + ); } else { content = ( {text} diff --git a/src/components/Tooltip/BaseGenericTooltip/index.tsx b/src/components/Tooltip/BaseGenericTooltip/index.tsx index 9ae49defc0fa..bfa84cd1830d 100644 --- a/src/components/Tooltip/BaseGenericTooltip/index.tsx +++ b/src/components/Tooltip/BaseGenericTooltip/index.tsx @@ -8,6 +8,7 @@ import TransparentOverlay from '@components/AutoCompleteSuggestions/AutoComplete import {PopoverContext} from '@components/PopoverProvider'; import Text from '@components/Text'; import useStyleUtils from '@hooks/useStyleUtils'; +import {parseFSAttributes} from '@libs/Fullstory'; import CONST from '@src/CONST'; import textRef from '@src/types/utils/textRef'; import viewRef from '@src/types/utils/viewRef'; @@ -120,14 +121,32 @@ function BaseGenericTooltip({ return StyleUtils.getTooltipAnimatedStyles({tooltipContentWidth: contentMeasuredWidth, tooltipWrapperHeight: wrapperMeasuredHeight, currentSize: animation}); }); + /** + * Extracts values from the non-scraped attribute WEB_PROP_ATTR at build time + * to ensure necessary properties are available for further processing. + * Reevaluates "fs-class" to dynamically apply styles or behavior based on + * updated attribute values. + */ + useLayoutEffect(parseFSAttributes, []); + let content; if (renderTooltipContent) { - content = {renderTooltipContent()}; + content = ( + + {renderTooltipContent()} + + ); } else { content = ( jest.fn()); jest.mock('@pages/settings/InitialSettingsPage'); jest.mock('@pages/settings/Profile/ProfilePage'); +// Mock Fullstory library dependency +jest.mock('@libs/Fullstory', () => ({ + default: { + consentAndIdentify: jest.fn(), + }, + parseFSAttributes: jest.fn(), +})); const INITIAL_STATE = { index: 0, diff --git a/tests/ui/components/ProductTrainingContextProvider.tsx b/tests/ui/components/ProductTrainingContextProvider.tsx index d54c8f8c446e..2cdb64c11824 100644 --- a/tests/ui/components/ProductTrainingContextProvider.tsx +++ b/tests/ui/components/ProductTrainingContextProvider.tsx @@ -15,6 +15,14 @@ jest.mock('@hooks/useResponsiveLayout', () => ({ default: jest.fn(), })); +// Mock Fullstory library dependency +jest.mock('@libs/Fullstory', () => ({ + default: { + consentAndIdentify: jest.fn(), + }, + parseFSAttributes: jest.fn(), +})); + const DEFAULT_USE_RESPONSIVE_LAYOUT_VALUE = { shouldUseNarrowLayout: true, isSmallScreenWidth: true,