Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Subscribe guides to a new presence pusher channel #48696

Merged
merged 11 commits into from
Sep 19, 2024
36 changes: 36 additions & 0 deletions src/components/ActiveGuidesEventListener.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {useEffect, useRef} from 'react';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import * as Report from '@userActions/Report';
import ONYXKEYS from '@src/ONYXKEYS';
import type {User} from '@src/types/onyx';

type ActiveGuidesEventListenerOnyxProps = {
user: OnyxEntry<User>;
};

type ActiveGuidesEventListenerProps = ActiveGuidesEventListenerOnyxProps;

function ActiveGuidesEventListener({user}: ActiveGuidesEventListenerProps) {
const didSubscribeToActiveGuides = useRef(false);
useEffect(
() => () => {
if (didSubscribeToActiveGuides.current) {
return;
}
if (user?.isGuide) {
didSubscribeToActiveGuides.current = true;
Report.subscribeToActiveGuides();
}
},

[user],
);
return null;
}

export default withOnyx<ActiveGuidesEventListenerProps, ActiveGuidesEventListenerOnyxProps>({
user: {
key: ONYXKEYS.USER,
},
})(ActiveGuidesEventListener);
11 changes: 8 additions & 3 deletions src/libs/Navigation/AppNavigator/AuthScreens.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -107,7 +108,7 @@ function getCentralPaneScreenInitialParams(screenName: CentralPaneName, initialR
}

function initializePusher() {
Pusher.init({
return Pusher.init({
appKey: CONFIG.PUSHER.APP_KEY,
cluster: CONFIG.PUSHER.CLUSTER,
authEndpoint: `${CONFIG.EXPENSIFY.DEFAULT_API_ROOT}api/AuthenticatePusher?`,
Expand Down Expand Up @@ -227,6 +228,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
[StyleUtils, shouldUseNarrowLayout, onboardingIsMediumOrLargerScreenWidth, styles],
);
const modal = useRef<OnyxTypes.Modal>({});
const [didPusherInit, setDidPusherInit] = useState(false);

let initialReportID: string | undefined;
const isInitialRender = useRef(true);
Expand Down Expand Up @@ -264,7 +266,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().
Expand Down Expand Up @@ -562,6 +566,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie
})}
</RootStack.Navigator>
</View>
{didPusherInit && <ActiveGuidesEventListener />}
</ComposeProviders>
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/libs/Pusher/pusher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function getChannel(channelName: string): Channel | undefined {
/**
* Binds an event callback to a channel + eventName
*/
function bindEventToChannel<EventName extends PusherEventName>(channel: Channel | undefined, eventName: EventName, eventCallback: (data: EventData<EventName>) => void = () => {}) {
function bindEventToChannel<EventName extends PusherEventName>(channel: Channel | undefined, eventName?: EventName, eventCallback: (data: EventData<EventName>) => void = () => {}) {
if (!eventName || !channel) {
return;
}
Expand Down Expand Up @@ -232,7 +232,7 @@ function bindEventToChannel<EventName extends PusherEventName>(channel: Channel
*/
function subscribe<EventName extends PusherEventName>(
channelName: string,
eventName: EventName,
eventName?: EventName,
eventCallback: (data: EventData<EventName>) => void = () => {},
onResubscribe = () => {},
): Promise<void> {
Expand Down
12 changes: 12 additions & 0 deletions src/libs/actions/Report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4087,6 +4087,16 @@ function markAsManuallyExported(reportID: string, connectionName: ConnectionName
API.write(WRITE_COMMANDS.MARK_AS_EXPORTED, params, {optimisticData, successData, failureData});
}

function subscribeToActiveGuides() {
Pusher.subscribe(`activeGuides`).catch((error: ReportError) => {
Log.hmmm('[Report] Failed to initially subscribe to Pusher channel', {errorType: error.type, pusherChanelName: 'activeGuides'});
});
}

function unsubscribeToActiveGuides() {
Pusher.unsubscribe(`activeGuides`);
}

export type {Video};

export {
Expand Down Expand Up @@ -4175,4 +4185,6 @@ export {
exportToIntegration,
markAsManuallyExported,
handleReportChanged,
subscribeToActiveGuides,
unsubscribeToActiveGuides,
};
3 changes: 3 additions & 0 deletions src/types/onyx/User.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ type User = {

/** Whether the form is being submitted */
loading?: boolean;

/** Whether the user is Expensify Guide */
isGuide?: boolean;
};

export default User;
Loading