diff --git a/packages/camera/src/components/Capture/capture.js b/packages/camera/src/components/Capture/capture.js index 32e2ed979..3cb278e0d 100644 --- a/packages/camera/src/components/Capture/capture.js +++ b/packages/camera/src/components/Capture/capture.js @@ -1,6 +1,7 @@ import { utils } from '@monkvision/toolkit'; +import { useMonitoring, MonitoringStatus, SentryTransaction, SentryOperation, SentryTag } from '@monkvision/corejs'; import PropTypes from 'prop-types'; -import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useState } from 'react'; +import React, { forwardRef, useCallback, useEffect, useRef, useImperativeHandle, useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ActivityIndicator, Platform, StyleSheet, Text, useWindowDimensions, View } from 'react-native'; @@ -122,9 +123,6 @@ const Capture = forwardRef(({ onPictureTaken, onWarningMessage, onReady, - onRetakeAll, - onRetakeNeeded, - onSkipRetake, onStartUploadPicture, onFinishUploadPicture, orientationBlockerProps, @@ -156,7 +154,9 @@ const Capture = forwardRef(({ }); const [endTour, setEndTour] = useState(false); const { height, width } = useWindowDimensions(); + const { errorHandler, measurePerformance } = useMonitoring(); + const captureTourTransRef = useRef({}); const { camera, ref } = combinedRefs.current; const { current } = sights.state; const portraitMediaQuery = useMediaQuery({ query: '(orientation: portrait)' }); @@ -244,6 +244,17 @@ const Capture = forwardRef(({ const checkComplianceParams = { compliance, inspectionId, sightId: current.id }; const checkComplianceAsync = useCheckComplianceAsync(checkComplianceParams); + const handleCaptureTourFinish = useCallback(() => { + /** + * finish 'capture tour' transaction successfully + * this function will be triggered when 'capture tour' ends + */ + if (!enableComplianceCheck) { + utils.log(['[Event] Capture-Tour sentry transaction finishes']); + captureTourTransRef.current.transaction.finish(); + } + onCaptureTourFinish(); + }, []); const startUploadAsyncParams = { inspectionId, sights, @@ -251,7 +262,7 @@ const Capture = forwardRef(({ task, mapTasksToSights, enableCarCoverage, - onFinish: onCaptureTourFinish, + onFinish: handleCaptureTourFinish, onPictureUploaded, onWarningMessage, endTour, @@ -348,6 +359,9 @@ const Capture = forwardRef(({ if (typeof onCloseEarly === 'function') { onCloseEarly(); } + // finish 'capture tour' transaction unsuccessfully + utils.log(['[Event] Capture-Tour sentry transaction cancels']); + captureTourTransRef.current.transaction.finish(MonitoringStatus.CANCELLED); setEndTour(true); }, [setEndTour]); @@ -377,14 +391,80 @@ const Capture = forwardRef(({ handleCloseCaptureEarly(); }, [setCloseEarlyModalState, handleCloseCaptureEarly]); + const handleComplianceCheckFinish = useCallback(() => { + /** + * finish 'capture tour' transaction successfully + * this function will be triggered only when + * enableComplianceCheck = true and UploadCenter component is rendered + */ + utils.log(['[Event] Capture-Tour sentry transaction finishes']); + captureTourTransRef.current.transaction.finish(); + onComplianceCheckFinish(); + }, []); + + const onRetakeAll = useCallback(() => { + captureTourTransRef.current.hasRetakeCalled = true; + captureTourTransRef.current.transaction.setTag(SentryTag.IS_RETAKE, 1); + }, []); + + const onSkipRetake = useCallback(() => { + captureTourTransRef.current.transaction.setTag(SentryTag.IS_SKIP, 1); + }, []); + + const onRetakeNeeded = useCallback(({ retakesNeeded = 0 }) => { + if (!captureTourTransRef.current.hasRetakeCalled) { + const { transaction } = captureTourTransRef.current; + const percentOfNonCompliancePics = ((100 * retakesNeeded) / states.sights.state.ids.length); + transaction.setTag(SentryTag.RETAKEN_PICTURES, retakesNeeded); + transaction.setTag(SentryTag.PERCENT_OF_NON_COMPLIANCE_PICS, percentOfNonCompliancePics); + } + }, []); + // END HANDLERS // // EFFECTS // + useEffect(() => { + /** + * create a new transaction with operation name 'Capture Tour' to measure tour performance + */ + utils.log(['[Event] Capture-Tour sentry transaction starts']); + const transaction = measurePerformance( + SentryTransaction.PICTURE_PROCESSING, + SentryOperation.CAPTURE_TOUR, + ); + // set tags to identify a transation and relate with an inspection + transaction.setTag(SentryTag.TASK, task); + transaction.setTag(SentryTag.INSPECTION_ID, inspectionId); + transaction.setTag(SentryTag.IS_SKIP, 0); + transaction.setTag(SentryTag.IS_RETAKE, 0); + transaction.setTag(SentryTag.TAKEN_PICTURES, 0); + transaction.setTag(SentryTag.RETAKEN_PICTURES, 0); + captureTourTransRef.current = { + transaction, + takenPictures: 0, + hasRetakeCalled: false, + }; + }, []); + useEffect(() => { try { + /** + * add takenPictures tag in "Capture Tour" transaction for a tour + */ + const takenPicturesLen = Object.values(states.sights.state.takenPictures).length; + const refObj = captureTourTransRef.current; + if (takenPicturesLen + && refObj.transaction + && !refObj.hasRetakeCalled + && takenPicturesLen !== refObj.takenPictures + ) { + refObj.takenPictures = takenPicturesLen; + refObj.transaction.setTag(SentryTag.TAKEN_PICTURES, takenPicturesLen); + } onChange(states, api); } catch (err) { log([`Error in \`\` \`onChange()\`: ${err}`], 'error'); + errorHandler(err); throw err; } }, [api, onChange, states]); @@ -483,7 +563,7 @@ const Capture = forwardRef(({ {}, onSettingsChange: () => {}, onSightsChange: () => {}, - onSkipRetake: () => {}, onUploadsChange: () => {}, onComplianceCheckFinish: () => {}, onComplianceCheckStart: () => {}, @@ -797,8 +873,6 @@ Capture.defaultProps = { onWarningMessage: () => {}, onReady: () => {}, onStartUploadPicture: () => {}, - onRetakeAll: () => {}, - onRetakeNeeded: () => {}, orientationBlockerProps: null, primaryColor: '#FFF', resolutionOptions: undefined, diff --git a/src/screens/InspectionCapture/index.js b/src/screens/InspectionCapture/index.js index a1db5e03a..51088b052 100644 --- a/src/screens/InspectionCapture/index.js +++ b/src/screens/InspectionCapture/index.js @@ -6,7 +6,7 @@ import { useTheme } from 'react-native-paper'; import { Alert, Platform, View } from 'react-native'; import { Capture, Controls } from '@monkvision/camera'; -import monk, { useMonitoring, MonitoringStatus, SentryTransaction, SentryOperation, SentryTag } from '@monkvision/corejs'; +import monk, { useMonitoring } from '@monkvision/corejs'; import { utils } from '@monkvision/toolkit'; import * as names from 'screens/names'; @@ -23,7 +23,7 @@ export default function InspectionCapture() { const dispatch = useDispatch(); const { t } = useTranslation(); const { colors } = useTheme(); - const { errorHandler, measurePerformance } = useMonitoring(); + const { errorHandler } = useMonitoring(); const { inspectionId, sightIds, taskName, vehicleType, selectedMode } = route.params; @@ -31,7 +31,6 @@ export default function InspectionCapture() { const [success, setSuccess] = useState(false); const [cameraLoading, setCameraLoading] = useState(false); const { setShowMessage, Notice } = useSnackbar(); - const captureTourTransRef = useRef({}); const { isFullscreen, requestFullscreen } = useFullscreen(); const handleNavigate = useCallback((confirm = false) => { @@ -40,11 +39,6 @@ export default function InspectionCapture() { // eslint-disable-next-line no-alert const ok = window.confirm(t('capture.quit.title')); if (ok) { - /** - * cancel 'Capture Tour' transaction and navigate back to landing page - */ - utils.log(['[Click]', 'User suddenly quit the inspection']); - captureTourTransRef.current.transaction.finish(MonitoringStatus.CANCELLED); navigation.navigate(names.LANDING, { inspectionId }); } } @@ -58,11 +52,6 @@ export default function InspectionCapture() { }, { text: t('capture.quit.ok'), onPress: () => { - /** - * cancel 'Capture Tour' transaction and navigate back to landing page - */ - utils.log(['[Click]', 'User suddenly quit the inspection']); - captureTourTransRef.current.transaction.finish(MonitoringStatus.CANCELLED); navigation.navigate(names.LANDING, { inspectionId }); }, }], @@ -103,10 +92,9 @@ export default function InspectionCapture() { setCameraLoading(false); /** - * finish 'capture tour' transaction and navigate back to landing page + * navigate back to landing page */ utils.log(['[Event] Back to landing page with photo taken']); - captureTourTransRef.current.transaction.finish(); handleNavigate(); } catch (err) { errorHandler(err); @@ -116,20 +104,6 @@ export default function InspectionCapture() { }, [dispatch, handleNavigate, inspectionId, success, taskName, isFocused]); const handleChange = useCallback((state) => { - /** - * add takenPictures tag in "Capture Tour" transaction for a tour - */ - const takenPicturesLen = Object.values(state.sights.state.takenPictures).length; - const refObj = captureTourTransRef.current; - if (takenPicturesLen - && refObj.transaction - && !refObj.hasRetakeCalled - && takenPicturesLen !== refObj.takenPictures - ) { - refObj.takenPictures = takenPicturesLen; - refObj.transaction.setTag(SentryTag.TAKEN_PICTURES, takenPicturesLen); - } - // if (!success && isFocused && !enableComplianceCheck) { try { const { takenPictures, tour } = state.sights.state; @@ -160,8 +134,6 @@ export default function InspectionCapture() { } } catch (err) { errorHandler(err); - // eslint-disable-next-line no-console - console.error(err); throw err; } } @@ -179,49 +151,19 @@ export default function InspectionCapture() { { disabled: cameraLoading, ...Controls.AddDamageButtonProps }, { disabled: cameraLoading, ...Controls.CaptureButtonProps }, ], - { disabled: cameraLoading, onPress: () => handleNavigate(true), ...Controls.GoBackButtonProps }, + { + ...Controls.CloseEarlyButtonProps, + confirm: true, + confirmationMessage: { + en: 'Your inspection is not complete, are you sure you want to stop it ?', + fr: 'Votre inspection n\'est pas complète, êtes-vous sûr(e) de vouloir l\'arrêter ?', + }, + disabled: cameraLoading, + }, ]; - const onRetakeAll = useCallback(() => { - captureTourTransRef.current.hasRetakeCalled = true; - captureTourTransRef.current.transaction.setTag(SentryTag.IS_RETAKE, 1); - }, []); - const onSkipRetake = useCallback(() => { - captureTourTransRef.current.transaction.setTag(SentryTag.IS_SKIP, 1); - }, []); - const onRetakeNeeded = useCallback(({ retakesNeeded = 0 }) => { - if (!captureTourTransRef.current.hasRetakeCalled) { - const { transaction } = captureTourTransRef.current; - const percentOfNonCompliancePics = ((100 * retakesNeeded) / sightIds.length); - transaction.setTag(SentryTag.RETAKEN_PICTURES, retakesNeeded); - transaction.setTag(SentryTag.PERCENT_OF_NON_COMPLIANCE_PICS, percentOfNonCompliancePics); - } - }, []); - useEffect(() => { if (success) { handleSuccess(); } }, [handleSuccess, success]); - useEffect(() => { - /** - * create a new transaction with operation name 'Capture Tour' to measure tour performance - */ - const transaction = measurePerformance( - SentryTransaction.PICTURE_PROCESSING, - SentryOperation.CAPTURE_TOUR, - ); - // set tags to identify a transation and relate with an inspection - transaction.setTag(SentryTag.TASK, taskName); - transaction.setTag(SentryTag.INSPECTION_ID, inspectionId); - transaction.setTag(SentryTag.IS_SKIP, 0); - transaction.setTag(SentryTag.IS_RETAKE, 0); - transaction.setTag(SentryTag.TAKEN_PICTURES, 0); - transaction.setTag(SentryTag.RETAKEN_PICTURES, 0); - captureTourTransRef.current = { - transaction, - takenPictures: 0, - hasRetakeCalled: false, - }; - }, []); - useFocusEffect(() => { setFocused(true); return () => setFocused(false); @@ -243,9 +185,6 @@ export default function InspectionCapture() { onFinishUploadPicture={() => setCameraLoading(false)} onWarningMessage={(message) => setShowMessage(message)} onChange={handleChange} - onRetakeAll={onRetakeAll} - onSkipRetake={onSkipRetake} - onRetakeNeeded={onRetakeNeeded} enableCarCoverage enableComplianceCheck={enableComplianceCheck} onComplianceCheckFinish={() => setSuccess(true)}