|
| 1 | +import {useNavigation} from '@react-navigation/native'; |
| 2 | +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; |
| 3 | +import {useOnyx} from 'react-native-onyx'; |
| 4 | +import {updateChatPriorityMode} from '@libs/actions/User'; |
| 5 | +import getIsNarrowLayout from '@libs/getIsNarrowLayout'; |
| 6 | +import Log from '@libs/Log'; |
| 7 | +import navigationRef from '@libs/Navigation/navigationRef'; |
| 8 | +import {isReportParticipant, isValidReport} from '@libs/ReportUtils'; |
| 9 | +import CONST from '@src/CONST'; |
| 10 | +import ONYXKEYS from '@src/ONYXKEYS'; |
| 11 | +import SCREENS from '@src/SCREENS'; |
| 12 | +import FocusModeNotification from './FocusModeNotification'; |
| 13 | + |
| 14 | +/** |
| 15 | + * This component is used to automatically switch a user into #focus mode when they exceed a certain number of reports. |
| 16 | + * We do this primarily for performance reasons. Similar to the "Welcome action" we must wait for a number of things to |
| 17 | + * happen when the user signs in or refreshes the page: |
| 18 | + * |
| 19 | + * - NVP that tracks whether they have already been switched over. We only do this once. |
| 20 | + * - Priority mode NVP (that dictates the ordering/filtering logic of the LHN) |
| 21 | + * - Reports to load (in ReconnectApp or OpenApp). As we check the count of the reports to determine whether the |
| 22 | + * user is eligible to be automatically switched. |
| 23 | + * |
| 24 | + */ |
| 25 | +export default function PriorityModeController() { |
| 26 | + const [accountID] = useOnyx(ONYXKEYS.SESSION, {selector: (session) => session?.accountID, canBeMissing: true}); |
| 27 | + const [isLoadingReportData] = useOnyx(ONYXKEYS.IS_LOADING_REPORT_DATA, {canBeMissing: true}); |
| 28 | + const [isInFocusMode] = useOnyx(ONYXKEYS.NVP_PRIORITY_MODE, {selector: (priorityMode) => priorityMode === CONST.PRIORITY_MODE.GSD, canBeMissing: true}); |
| 29 | + const [hasTriedFocusMode] = useOnyx(ONYXKEYS.NVP_TRY_FOCUS_MODE, {canBeMissing: true}); |
| 30 | + const [allReports] = useOnyx(ONYXKEYS.COLLECTION.REPORT, {canBeMissing: true}); |
| 31 | + const currentRouteName = useCurrentRouteName(); |
| 32 | + const [shouldShowModal, setShouldShowModal] = useState(false); |
| 33 | + const closeModal = useCallback(() => setShouldShowModal(false), []); |
| 34 | + |
| 35 | + const validReportCount = useMemo(() => { |
| 36 | + let count = 0; |
| 37 | + Object.values(allReports ?? {}).forEach((report) => { |
| 38 | + if (!isValidReport(report) || !isReportParticipant(accountID ?? CONST.DEFAULT_NUMBER_ID, report)) { |
| 39 | + return; |
| 40 | + } |
| 41 | + |
| 42 | + count++; |
| 43 | + }); |
| 44 | + return count; |
| 45 | + }, [accountID, allReports]); |
| 46 | + |
| 47 | + // We set this when we have finally auto-switched the user of #focus mode to prevent duplication. |
| 48 | + const hasSwitched = useRef(false); |
| 49 | + |
| 50 | + // Listen for state changes and trigger the #focus mode when appropriate |
| 51 | + useEffect(() => { |
| 52 | + // Wait for Onyx state to fully load |
| 53 | + if (isLoadingReportData !== false || isInFocusMode === undefined || hasTriedFocusMode === undefined || !accountID) { |
| 54 | + return; |
| 55 | + } |
| 56 | + |
| 57 | + if (hasSwitched.current || isInFocusMode || hasTriedFocusMode) { |
| 58 | + return; |
| 59 | + } |
| 60 | + |
| 61 | + if (validReportCount < CONST.REPORT.MAX_COUNT_BEFORE_FOCUS_UPDATE) { |
| 62 | + Log.info('[PriorityModeController] Not switching user to focus mode as they do not have enough reports', false, {validReportCount}); |
| 63 | + return; |
| 64 | + } |
| 65 | + |
| 66 | + // We wait for the user to navigate back to the home screen before triggering this switch |
| 67 | + const isNarrowLayout = getIsNarrowLayout(); |
| 68 | + if ((isNarrowLayout && currentRouteName !== SCREENS.HOME) || (!isNarrowLayout && currentRouteName !== SCREENS.REPORT)) { |
| 69 | + Log.info("[PriorityModeController] Not switching user to focus mode as they aren't on the home screen", false, {validReportCount, currentRouteName}); |
| 70 | + return; |
| 71 | + } |
| 72 | + |
| 73 | + Log.info('[PriorityModeController] Switching user to focus mode', false, {validReportCount, hasTriedFocusMode, isInFocusMode, currentRouteName}); |
| 74 | + updateChatPriorityMode(CONST.PRIORITY_MODE.GSD, true); |
| 75 | + setShouldShowModal(true); |
| 76 | + hasSwitched.current = true; |
| 77 | + }, [accountID, currentRouteName, hasTriedFocusMode, isInFocusMode, isLoadingReportData, validReportCount]); |
| 78 | + |
| 79 | + return shouldShowModal ? <FocusModeNotification onClose={closeModal} /> : null; |
| 80 | +} |
| 81 | + |
| 82 | +/** |
| 83 | + * A funky but reliable way to subscribe to screen changes. |
| 84 | + */ |
| 85 | +function useCurrentRouteName() { |
| 86 | + const navigation = useNavigation(); |
| 87 | + const [currentRouteName, setCurrentRouteName] = useState<string | undefined>(''); |
| 88 | + |
| 89 | + useEffect(() => { |
| 90 | + const unsubscribe = navigation.addListener('state', () => { |
| 91 | + setCurrentRouteName(navigationRef.getCurrentRoute()?.name); |
| 92 | + }); |
| 93 | + return () => unsubscribe(); |
| 94 | + }, [navigation]); |
| 95 | + |
| 96 | + return currentRouteName; |
| 97 | +} |
0 commit comments