diff --git a/src/CONST.ts b/src/CONST.ts index 8698c59f8b84..8100465f7c79 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -1262,6 +1262,7 @@ const CONST = { PUSHER: { PRIVATE_USER_CHANNEL_PREFIX: 'private-encrypted-user-accountID-', PRIVATE_REPORT_CHANNEL_PREFIX: 'private-report-reportID-', + PRESENCE_ACTIVE_GUIDES: 'presence-activeGuides', }, EMOJI_SPACER: 'SPACER', diff --git a/src/components/ActiveGuidesEventListener.tsx b/src/components/ActiveGuidesEventListener.tsx new file mode 100644 index 000000000000..2599576c9c23 --- /dev/null +++ b/src/components/ActiveGuidesEventListener.tsx @@ -0,0 +1,21 @@ +import {useEffect, useRef} from 'react'; +import {useOnyx} from 'react-native-onyx'; +import {subscribeToActiveGuides} from '@userActions/User'; +import ONYXKEYS from '@src/ONYXKEYS'; + +function ActiveGuidesEventListener() { + const [user] = useOnyx(ONYXKEYS.USER); + const didSubscribeToActiveGuides = useRef(false); + useEffect(() => { + if (didSubscribeToActiveGuides.current) { + return; + } + if (user?.isGuide) { + didSubscribeToActiveGuides.current = true; + subscribeToActiveGuides(); + } + }, [user]); + return null; +} + +export default ActiveGuidesEventListener; diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 5a84657d1677..dee84a4f201f 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -1,8 +1,9 @@ -import React, {memo, useEffect, useMemo, useRef} from 'react'; +import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; import Onyx, {withOnyx} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; +import ActiveGuidesEventListener from '@components/ActiveGuidesEventListener'; import ComposeProviders from '@components/ComposeProviders'; import OptionsListContextProvider from '@components/OptionListContextProvider'; import {SearchContextProvider} from '@components/Search/SearchContext'; @@ -117,7 +118,7 @@ function getCentralPaneScreenListeners(screenName: CentralPaneName) { } function initializePusher() { - Pusher.init({ + return Pusher.init({ appKey: CONFIG.PUSHER.APP_KEY, cluster: CONFIG.PUSHER.CLUSTER, authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`, @@ -235,6 +236,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie [StyleUtils, shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, styles], ); const modal = useRef({}); + const [didPusherInit, setDidPusherInit] = useState(false); let initialReportID: string | undefined; const isInitialRender = useRef(true); @@ -272,7 +274,9 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie NetworkConnection.listenForReconnect(); NetworkConnection.onReconnect(handleNetworkReconnect); PusherConnectionManager.init(); - initializePusher(); + initializePusher().then(() => { + setDidPusherInit(true); + }); // If we are on this screen then we are "logged in", but the user might not have "just logged in". They could be reopening the app // or returning from background. If so, we'll assume they have some app data already and we can call reconnectApp() instead of openApp(). @@ -572,6 +576,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie + {didPusherInit && } ); } diff --git a/src/libs/Pusher/pusher.ts b/src/libs/Pusher/pusher.ts index a3383dbadb8a..1a511eec391c 100644 --- a/src/libs/Pusher/pusher.ts +++ b/src/libs/Pusher/pusher.ts @@ -156,7 +156,7 @@ function getChannel(channelName: string): Channel | undefined { /** * Binds an event callback to a channel + eventName */ -function bindEventToChannel(channel: Channel | undefined, eventName: EventName, eventCallback: (data: EventData) => void = () => {}) { +function bindEventToChannel(channel: Channel | undefined, eventName?: EventName, eventCallback: (data: EventData) => void = () => {}) { if (!eventName || !channel) { return; } @@ -232,7 +232,7 @@ function bindEventToChannel(channel: Channel */ function subscribe( channelName: string, - eventName: EventName, + eventName?: EventName, eventCallback: (data: EventData) => void = () => {}, onResubscribe = () => {}, ): Promise { diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index eb78da49cdda..7ef7d6b94c9e 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -33,6 +33,7 @@ import * as ReportActionsUtils from '@libs/ReportActionsUtils'; import playSound, {SOUNDS} from '@libs/Sound'; import playSoundExcludingMobile from '@libs/Sound/playSoundExcludingMobile'; import Visibility from '@libs/Visibility'; +import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; @@ -1327,6 +1328,13 @@ function requestRefund() { API.write(WRITE_COMMANDS.REQUEST_REFUND, null); } +function subscribeToActiveGuides() { + const pusherChannelName = `${CONST.PUSHER.PRESENCE_ACTIVE_GUIDES}${CONFIG.PUSHER.SUFFIX}`; + Pusher.subscribe(pusherChannelName).catch(() => { + Log.hmmm('[User] Failed to initially subscribe to Pusher channel', {pusherChannelName}); + }); +} + function setIsDebugModeEnabled(isDebugModeEnabled: boolean) { Onyx.merge(ONYXKEYS.USER, {isDebugModeEnabled}); } @@ -1369,6 +1377,7 @@ export { requestValidateCodeAction, addPendingContactMethod, clearValidateCodeActionError, + subscribeToActiveGuides, dismissGBRTooltip, setIsDebugModeEnabled, }; diff --git a/src/types/onyx/User.ts b/src/types/onyx/User.ts index a7bb60ea12e6..56b7a83d1618 100644 --- a/src/types/onyx/User.ts +++ b/src/types/onyx/User.ts @@ -30,6 +30,9 @@ type User = { /** Whether the form is being submitted */ loading?: boolean; + /** Whether the user is Expensify Guide */ + isGuide?: boolean; + /** Whether the debug mode is currently enabled */ isDebugModeEnabled?: boolean; };