diff --git a/src/CONST/index.ts b/src/CONST/index.ts index f9d3b3877584..fcab3ff96b4b 100644 --- a/src/CONST/index.ts +++ b/src/CONST/index.ts @@ -1795,6 +1795,7 @@ const CONST = { SPAN_SEARCH_ROUTER_COMPUTE_OPTIONS: 'SearchRouter.ComputeOptions', SPAN_SEARCH_ROUTER_LIST_RENDER: 'SearchRouter.ListRender', SPAN_OPEN_CREATE_EXPENSE: 'ManualOpenCreateExpense', + SPAN_SCAN_SHORTCUT: 'ScanShortcut', SPAN_CAMERA_INIT: 'ManualCameraInit', SPAN_SHUTTER_TO_CONFIRMATION: 'ManualShutterToConfirmation', SPAN_RECEIPT_CAPTURE: 'ManualReceiptCapture', diff --git a/src/components/FloatingCameraButton/BaseFloatingCameraButton.tsx b/src/components/FloatingCameraButton/BaseFloatingCameraButton.tsx index 61aec9e812fb..6ec88ed53a2f 100644 --- a/src/components/FloatingCameraButton/BaseFloatingCameraButton.tsx +++ b/src/components/FloatingCameraButton/BaseFloatingCameraButton.tsx @@ -13,6 +13,7 @@ import interceptAnonymousUser from '@libs/interceptAnonymousUser'; import Navigation from '@libs/Navigation/Navigation'; import {generateReportID, getWorkspaceChats} from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; +import {startSpan} from '@libs/telemetry/activeSpans'; import variables from '@styles/variables'; import Tab from '@userActions/Tab'; import CONST from '@src/CONST'; @@ -61,6 +62,10 @@ function BaseFloatingCameraButton({icon}: BaseFloatingCameraButtonProps) { const quickActionReportID = policyChatForActivePolicy?.reportID ?? reportID; Tab.setSelectedTab(CONST.TAB.IOU_REQUEST_TYPE, CONST.IOU.REQUEST_TYPE.SCAN); + startSpan(CONST.TELEMETRY.SPAN_SCAN_SHORTCUT, { + name: CONST.TELEMETRY.SPAN_SCAN_SHORTCUT, + op: CONST.TELEMETRY.SPAN_SCAN_SHORTCUT, + }); startMoneyRequest(CONST.IOU.TYPE.CREATE, quickActionReportID, CONST.IOU.REQUEST_TYPE.SCAN, !!policyChatForActivePolicy?.reportID, undefined, allTransactionDrafts, true); }); }; diff --git a/src/libs/actions/IOU/index.ts b/src/libs/actions/IOU/index.ts index ae71aade3154..ac979d93f6d7 100644 --- a/src/libs/actions/IOU/index.ts +++ b/src/libs/actions/IOU/index.ts @@ -1374,7 +1374,10 @@ function startMoneyRequest( }); clearMoneyRequest(CONST.IOU.OPTIMISTIC_TRANSACTION_ID, skipConfirmation, draftTransactions); if (isFromFloatingActionButton) { - Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, {isFromFloatingActionButton}); + Onyx.set(`${ONYXKEYS.COLLECTION.TRANSACTION_DRAFT}${CONST.IOU.OPTIMISTIC_TRANSACTION_ID}`, { + isFromFloatingActionButton, + ...(requestType && {iouRequestType: requestType}), + }); } switch (requestType) { case CONST.IOU.REQUEST_TYPE.MANUAL: diff --git a/src/pages/inbox/sidebar/FloatingActionButtonAndPopover.tsx b/src/pages/inbox/sidebar/FloatingActionButtonAndPopover.tsx index e91245da4ed1..590adc16d095 100644 --- a/src/pages/inbox/sidebar/FloatingActionButtonAndPopover.tsx +++ b/src/pages/inbox/sidebar/FloatingActionButtonAndPopover.tsx @@ -57,6 +57,7 @@ import { isPolicyExpenseChat, } from '@libs/ReportUtils'; import {shouldRestrictUserBillableActions} from '@libs/SubscriptionUtils'; +import {startSpan} from '@libs/telemetry/activeSpans'; import isOnSearchMoneyRequestReportPage from '@navigation/helpers/isOnSearchMoneyRequestReportPage'; import variables from '@styles/variables'; import {closeReactNativeApp} from '@userActions/HybridApp'; @@ -366,6 +367,11 @@ function FloatingActionButtonAndPopover({onHideCreateMenu, onShowCreateMenu, ref const quickActionReportID = policyChatForActivePolicy?.reportID ?? reportID; Tab.setSelectedTab(CONST.TAB.IOU_REQUEST_TYPE, CONST.IOU.REQUEST_TYPE.SCAN); + // Scan shortcut span: green receipt button (web sidebar) and camera FAB (narrow/mobile) + startSpan(CONST.TELEMETRY.SPAN_SCAN_SHORTCUT, { + name: CONST.TELEMETRY.SPAN_SCAN_SHORTCUT, + op: CONST.TELEMETRY.SPAN_SCAN_SHORTCUT, + }); startMoneyRequest(CONST.IOU.TYPE.CREATE, quickActionReportID, CONST.IOU.REQUEST_TYPE.SCAN, !!policyChatForActivePolicy?.reportID, undefined, allTransactionDrafts, true); }); }, [policyChatForActivePolicy?.policyID, policyChatForActivePolicy?.reportID, reportID, allTransactionDrafts]); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index c2044a833ed5..d50c2e53271c 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -51,6 +51,7 @@ import NavigationAwareCamera from './NavigationAwareCamera/Camera'; import ReceiptPreviews from './ReceiptPreviews'; import type IOURequestStepScanProps from './types'; import useReceiptScan from './useReceiptScan'; +import useScanShortcutSpan from './useScanShortcutSpan'; function IOURequestStepScan({ report, @@ -95,6 +96,8 @@ function IOURequestStepScan({ const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${report?.policyID}`); + useScanShortcutSpan(initialTransaction); + // Track camera init telemetry const cameraInitSpanStarted = useRef(false); const cameraInitialized = useRef(false); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.tsx index db87e8183711..2c4bb84001d9 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.tsx @@ -49,6 +49,7 @@ import NavigationAwareCamera from './NavigationAwareCamera/WebCamera'; import ReceiptPreviews from './ReceiptPreviews'; import type IOURequestStepScanProps from './types'; import useReceiptScan from './useReceiptScan'; +import useScanShortcutSpan from './useScanShortcutSpan'; function IOURequestStepScan({ report, @@ -86,6 +87,8 @@ function IOURequestStepScan({ endSpan(CONST.TELEMETRY.SPAN_OPEN_CREATE_EXPENSE); }, []); + useScanShortcutSpan(initialTransaction); + const navigateBack = useCallback(() => { Navigation.goBack(backTo); }, [backTo]); diff --git a/src/pages/iou/request/step/IOURequestStepScan/useScanShortcutSpan.ts b/src/pages/iou/request/step/IOURequestStepScan/useScanShortcutSpan.ts new file mode 100644 index 000000000000..369c81bc4445 --- /dev/null +++ b/src/pages/iou/request/step/IOURequestStepScan/useScanShortcutSpan.ts @@ -0,0 +1,22 @@ +import {useLayoutEffect} from 'react'; +import type {OnyxEntry} from 'react-native-onyx'; +import {cancelSpan, endSpan} from '@libs/telemetry/activeSpans'; +import CONST from '@src/CONST'; +import type Transaction from '@src/types/onyx/Transaction'; + +/** + * Ends the scan shortcut Sentry span when the Scan page finishes first render, + * only when the flow was started from the green receipt FAB (isFromFloatingActionButton + request type SCAN). + */ +function useScanShortcutSpan(initialTransaction: OnyxEntry) { + const isFromScanShortcut = initialTransaction?.isFromFloatingActionButton === true && initialTransaction?.iouRequestType === CONST.IOU.REQUEST_TYPE.SCAN; + useLayoutEffect(() => { + if (!isFromScanShortcut) { + return; + } + endSpan(CONST.TELEMETRY.SPAN_SCAN_SHORTCUT); + return () => cancelSpan(CONST.TELEMETRY.SPAN_SCAN_SHORTCUT); + }, [isFromScanShortcut]); +} + +export default useScanShortcutSpan;