From f901cb5e198b140e79c2afcbd9ed75314e6b1a4e Mon Sep 17 00:00:00 2001 From: Jack Senyitko Date: Mon, 16 Mar 2026 09:08:58 -0400 Subject: [PATCH 1/8] track event --- src/CONST/index.ts | 1 + src/components/ProductTrainingContext/index.tsx | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index f2d66c6656c65..95aa36de54991 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -8227,6 +8227,7 @@ const CONST = { SIGN_UP: 'sign_up', WORKSPACE_CREATED: 'workspace_created', PAID_ADOPTION: 'paid_adoption', + PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN: 'product_training_scan_test_tooltip_shown', }, }, diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index 36d09312c6eb4..8c3c437b22c41 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -14,6 +14,7 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSidePanelState from '@hooks/useSidePanelState'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import GoogleTagManager from '@libs/GoogleTagManager'; import {getActiveAdminWorkspaces, getActiveEmployeeWorkspaces, getGroupPaidPoliciesWithExpenseChatEnabled} from '@libs/PolicyUtils'; import isProductTrainingElementDismissed from '@libs/TooltipUtils'; import variables from '@styles/variables'; @@ -254,6 +255,14 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou return shouldShow && shouldRenderTooltip(tooltipName) && !shouldHideToolTip; }, [shouldRenderTooltip, tooltipName, shouldShow, shouldHideToolTip]); + useEffect(() => { + if (!shouldShowProductTrainingTooltip || tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER) { + return; + } + + GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.WORKSPACE_CREATED, userAccountID); + }, [shouldShowProductTrainingTooltip, tooltipName]); + const hideTooltip = useCallback( (isDismissedUsingCloseButton = false) => { if (!shouldShowProductTrainingTooltip) { @@ -268,6 +277,7 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou const renderProductTrainingTooltip = useCallback(() => { const tooltip = TOOLTIPS[tooltipName]; + return ( Date: Mon, 16 Mar 2026 09:11:56 -0400 Subject: [PATCH 2/8] add user account id --- src/components/ProductTrainingContext/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index 8c3c437b22c41..b0ac975f0b32f 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -7,6 +7,7 @@ import Button from '@components/Button'; import Icon from '@components/Icon'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import RenderHTML from '@components/RenderHTML'; +import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -233,6 +234,7 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou const theme = useTheme(); const {shouldHideToolTip} = useSidePanelState(); const {translate} = useLocalize(); + const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['Close', 'Lightbulb'] as const); if (!context) { @@ -260,7 +262,7 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou return; } - GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.WORKSPACE_CREATED, userAccountID); + GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN, userAccountID); }, [shouldShowProductTrainingTooltip, tooltipName]); const hideTooltip = useCallback( From febc183960179536b6944d099c23363c33ff703a Mon Sep 17 00:00:00 2001 From: Jack Senyitko Date: Mon, 16 Mar 2026 09:12:13 -0400 Subject: [PATCH 3/8] add account id --- src/components/ProductTrainingContext/index.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index b0ac975f0b32f..e6e15b631dc1e 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -234,7 +234,7 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou const theme = useTheme(); const {shouldHideToolTip} = useSidePanelState(); const {translate} = useLocalize(); - const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails(); + const {accountID} = useCurrentUserPersonalDetails(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['Close', 'Lightbulb'] as const); if (!context) { @@ -262,8 +262,8 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou return; } - GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN, userAccountID); - }, [shouldShowProductTrainingTooltip, tooltipName]); + GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN, accountID); + }, [shouldShowProductTrainingTooltip, tooltipName, accountID]); const hideTooltip = useCallback( (isDismissedUsingCloseButton = false) => { From a8640eb7fff4813652781fbedfb995d11fb3460a Mon Sep 17 00:00:00 2001 From: Jack Senyitko Date: Mon, 16 Mar 2026 09:17:12 -0400 Subject: [PATCH 4/8] update event we're tracking --- src/components/ProductTrainingContext/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index e6e15b631dc1e..99c3873b230d4 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -258,7 +258,7 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou }, [shouldRenderTooltip, tooltipName, shouldShow, shouldHideToolTip]); useEffect(() => { - if (!shouldShowProductTrainingTooltip || tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP_MANAGER) { + if (!shouldShowProductTrainingTooltip || tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP) { return; } From 457e4b19ce57656319973d9cc841b58fac603346 Mon Sep 17 00:00:00 2001 From: Jack Senyitko Date: Mon, 16 Mar 2026 09:36:21 -0400 Subject: [PATCH 5/8] add an on show method --- src/components/ProductTrainingContext/index.tsx | 14 ++++++++------ src/pages/iou/request/IOURequestStartPage.tsx | 5 +++++ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index 99c3873b230d4..04f844cbce0ee 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -7,7 +7,6 @@ import Button from '@components/Button'; import Icon from '@components/Icon'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; import RenderHTML from '@components/RenderHTML'; -import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails'; import {useMemoizedLazyExpensifyIcons} from '@hooks/useLazyAsset'; import useLocalize from '@hooks/useLocalize'; import useOnyx from '@hooks/useOnyx'; @@ -15,7 +14,6 @@ import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useSidePanelState from '@hooks/useSidePanelState'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; -import GoogleTagManager from '@libs/GoogleTagManager'; import {getActiveAdminWorkspaces, getActiveEmployeeWorkspaces, getGroupPaidPoliciesWithExpenseChatEnabled} from '@libs/PolicyUtils'; import isProductTrainingElementDismissed from '@libs/TooltipUtils'; import variables from '@styles/variables'; @@ -43,6 +41,11 @@ type ProductTrainingContextConfig = { * Callback to be called when the tooltip is confirmed */ onConfirm?: () => void; + + /** + * Callback to be called when the tooltip is shown + */ + onShow?: () => void; }; const ProductTrainingContext = createContext({ @@ -234,7 +237,6 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou const theme = useTheme(); const {shouldHideToolTip} = useSidePanelState(); const {translate} = useLocalize(); - const {accountID} = useCurrentUserPersonalDetails(); const expensifyIcons = useMemoizedLazyExpensifyIcons(['Close', 'Lightbulb'] as const); if (!context) { @@ -258,12 +260,12 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou }, [shouldRenderTooltip, tooltipName, shouldShow, shouldHideToolTip]); useEffect(() => { - if (!shouldShowProductTrainingTooltip || tooltipName !== CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP) { + if (!shouldShowProductTrainingTooltip) { return; } - GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN, accountID); - }, [shouldShowProductTrainingTooltip, tooltipName, accountID]); + config.onShow?.(); + }, [shouldShowProductTrainingTooltip, config]); const hideTooltip = useCallback( (isDismissedUsingCloseButton = false) => { diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index 21b5278b84d83..f9055a88cf217 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -25,6 +25,7 @@ import {canUseTouchScreen} from '@libs/DeviceCapabilities'; import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID'; import getPlatform from '@libs/getPlatform'; import type Platform from '@libs/getPlatform/types'; +import GoogleTagManager from '@libs/GoogleTagManager'; import Navigation from '@libs/Navigation/Navigation'; import OnyxTabNavigator, {TabScreenWithFocusTrapWrapper, TopTab} from '@libs/Navigation/OnyxTabNavigator'; import { @@ -78,6 +79,7 @@ function IOURequestStartPage({ }: IOURequestStartPageProps) { const styles = useThemeStyles(); const {translate} = useLocalize(); + const {accountID} = useCurrentUserPersonalDetails(); const shouldUseTab = iouType !== CONST.IOU.TYPE.SEND && iouType !== CONST.IOU.TYPE.PAY && iouType !== CONST.IOU.TYPE.INVOICE; const personalPolicy = usePersonalPolicy(); const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`); @@ -260,6 +262,9 @@ function IOURequestStartPage({ // The test receipt image is served via our server on web so it requires internet connection !hasUserSubmittedExpenseOrScannedReceipt && isBetaEnabled(CONST.BETAS.NEWDOT_MANAGER_MCTEST) && selectedTab === CONST.TAB_REQUEST.SCAN && !(isOffline && isWeb), { + onShow: () => { + GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN, accountID); + }, onConfirm: () => { setTestReceiptAndNavigateRef?.current?.(); }, From b4185cd5d2352afda9cedf4420ef71ccd0317bf0 Mon Sep 17 00:00:00 2001 From: Jack Senyitko Date: Mon, 16 Mar 2026 09:39:50 -0400 Subject: [PATCH 6/8] add google tag events --- src/CONST/index.ts | 2 ++ src/pages/iou/request/IOURequestStartPage.tsx | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/CONST/index.ts b/src/CONST/index.ts index 95aa36de54991..3164308ec71fb 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -8228,6 +8228,8 @@ const CONST = { WORKSPACE_CREATED: 'workspace_created', PAID_ADOPTION: 'paid_adoption', PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN: 'product_training_scan_test_tooltip_shown', + PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_DISMISSED: 'product_training_scan_test_tooltip_dismissed', + PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_CONFIRMED: 'product_training_scan_test_tooltip_confirmed', }, }, diff --git a/src/pages/iou/request/IOURequestStartPage.tsx b/src/pages/iou/request/IOURequestStartPage.tsx index f9055a88cf217..965134e4b77ac 100644 --- a/src/pages/iou/request/IOURequestStartPage.tsx +++ b/src/pages/iou/request/IOURequestStartPage.tsx @@ -267,9 +267,11 @@ function IOURequestStartPage({ }, onConfirm: () => { setTestReceiptAndNavigateRef?.current?.(); + GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_CONFIRMED, accountID); }, onDismiss: () => { dismissProductTraining(CONST.PRODUCT_TRAINING_TOOLTIP_NAMES.SCAN_TEST_TOOLTIP, true); + GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_DISMISSED, accountID); }, }, ); From e16eddc65bf17feb6c6685d115d167ca364154a9 Mon Sep 17 00:00:00 2001 From: Jack Senyitko Date: Mon, 16 Mar 2026 09:43:46 -0400 Subject: [PATCH 7/8] use onLayout for consistency --- src/components/ProductTrainingContext/index.tsx | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index 04f844cbce0ee..d6df176898db8 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -259,14 +259,6 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou return shouldShow && shouldRenderTooltip(tooltipName) && !shouldHideToolTip; }, [shouldRenderTooltip, tooltipName, shouldShow, shouldHideToolTip]); - useEffect(() => { - if (!shouldShowProductTrainingTooltip) { - return; - } - - config.onShow?.(); - }, [shouldShowProductTrainingTooltip, config]); - const hideTooltip = useCallback( (isDismissedUsingCloseButton = false) => { if (!shouldShowProductTrainingTooltip) { @@ -283,7 +275,10 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou const tooltip = TOOLTIPS[tooltipName]; return ( - + Date: Mon, 16 Mar 2026 09:44:14 -0400 Subject: [PATCH 8/8] rename to onShown --- src/components/ProductTrainingContext/index.tsx | 6 +++--- src/pages/iou/request/IOURequestStartPage.tsx | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/ProductTrainingContext/index.tsx b/src/components/ProductTrainingContext/index.tsx index d6df176898db8..d3b63e9d1fd3d 100644 --- a/src/components/ProductTrainingContext/index.tsx +++ b/src/components/ProductTrainingContext/index.tsx @@ -45,7 +45,7 @@ type ProductTrainingContextConfig = { /** * Callback to be called when the tooltip is shown */ - onShow?: () => void; + onShown?: () => void; }; const ProductTrainingContext = createContext({ @@ -277,7 +277,7 @@ const useProductTrainingContext = (tooltipName: ProductTrainingTooltipName, shou return ( { + onShown: () => { GoogleTagManager.publishEvent(CONST.ANALYTICS.EVENT.PRODUCT_TRAINING_SCAN_TEST_TOOLTIP_SHOWN, accountID); }, onConfirm: () => {