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

fix unsubscribe is typing event if not focus on screen #39347

Merged
merged 16 commits into from
Apr 15, 2024
8 changes: 3 additions & 5 deletions src/pages/home/report/ReportActionsList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -348,12 +348,10 @@ function ReportActionsList({
const unsubscribe = Report.subscribeToNewActionEvent(report.reportID, scrollToBottomForCurrentUserAction);

const cleanup = () => {
if (unsubscribe) {
unsubscribe();
if (!unsubscribe) {
return;
}
InteractionManager.runAfterInteractions(() => {
Report.unsubscribeFromReportChannel(report.reportID);
});
unsubscribe();
};

newActionUnsubscribeMap[report.reportID] = cleanup;
Expand Down
28 changes: 4 additions & 24 deletions src/pages/home/report/ReportActionsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {useIsFocused, useRoute} from '@react-navigation/native';
import lodashIsEqual from 'lodash/isEqual';
import React, {useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react';
import {InteractionManager} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import type {OnyxEntry} from 'react-native-onyx';
import {withOnyx} from 'react-native-onyx';
import useCopySelectionHelper from '@hooks/useCopySelectionHelper';
import useInitialValue from '@hooks/useInitialValue';
import useNetwork from '@hooks/useNetwork';
Expand All @@ -17,8 +17,8 @@ import * as NumberUtils from '@libs/NumberUtils';
import {generateNewRandomInt} from '@libs/NumberUtils';
import Performance from '@libs/Performance';
import * as ReportActionsUtils from '@libs/ReportActionsUtils';
import {isUserCreatedPolicyRoom} from '@libs/ReportUtils';
import * as ReportUtils from '@libs/ReportUtils';
import {isUserCreatedPolicyRoom} from '@libs/ReportUtils';
import {didUserLogInDuringSession} from '@libs/SessionUtils';
import shouldFetchReport from '@libs/shouldFetchReport';
import {ReactionListContext} from '@pages/home/ReportScreenContext';
Expand All @@ -32,6 +32,7 @@ import {isEmptyObject} from '@src/types/utils/EmptyObject';
import getInitialPaginationSize from './getInitialPaginationSize';
import PopoverReactionList from './ReactionList/PopoverReactionList';
import ReportActionsList from './ReportActionsList';
import UserTypingEventListener from './UserTypingEventListener';

type ReportActionsViewOnyxProps = {
/** Session info for the currently logged in user. */
Expand Down Expand Up @@ -93,7 +94,6 @@ function ReportActionsView({
const route = useRoute<RouteProp<CentralPaneNavigatorParamList, typeof SCREENS.REPORT>>();
const reportActionID = route?.params?.reportActionID;
const didLayout = useRef(false);
const didSubscribeToReportTypingEvents = useRef(false);

// triggerListID is used when navigating to a chat with messages loaded from LHN. Typically, these include thread actions, task actions, etc. Since these messages aren't the latest,we don't maintain their position and instead trigger a recalculation of their positioning in the list.
// we don't set currentReportActionID on initial render as linkedID as it should trigger visibleReportActions after linked message was positioned
Expand Down Expand Up @@ -287,27 +287,6 @@ function ReportActionsView({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSmallScreenWidth, reportActions, isReportFullyVisible]);

useEffect(() => {
// Ensures the optimistic report is created successfully
if (route?.params?.reportID !== reportID) {
return;
}
// Ensures subscription event succeeds when the report/workspace room is created optimistically.
// Check if the optimistic `OpenReport` or `AddWorkspaceRoom` has succeeded by confirming
// any `pendingFields.createChat` or `pendingFields.addWorkspaceRoom` fields are set to null.
// Existing reports created will have empty fields for `pendingFields`.
const didCreateReportSuccessfully = !report.pendingFields || (!report.pendingFields.addWorkspaceRoom && !report.pendingFields.createChat);
if (!didSubscribeToReportTypingEvents.current && didCreateReportSuccessfully) {
const interactionTask = InteractionManager.runAfterInteractions(() => {
Report.subscribeToReportTypingEvents(reportID);
didSubscribeToReportTypingEvents.current = true;
});
return () => {
interactionTask.cancel();
};
}
}, [report.pendingFields, didSubscribeToReportTypingEvents, route, reportID]);

const onContentSizeChange = useCallback((w: number, h: number) => {
contentListHeight.current = h;
}, []);
Expand Down Expand Up @@ -529,6 +508,7 @@ function ReportActionsView({
onContentSizeChange={onContentSizeChange}
shouldEnableAutoScrollToTopThreshold={shouldEnableAutoScroll}
/>
<UserTypingEventListener report={report} />
<PopoverReactionList ref={reactionListRef} />
</>
);
Expand Down
71 changes: 71 additions & 0 deletions src/pages/home/report/UserTypingEventListener.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type {RouteProp} from '@react-navigation/native';
import {useIsFocused, useRoute} from '@react-navigation/native';
import {useEffect, useRef} from 'react';
import {InteractionManager} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import Navigation from '@libs/Navigation/Navigation';
import type {CentralPaneNavigatorParamList} from '@libs/Navigation/types';
import * as Report from '@userActions/Report';
import ONYXKEYS from '@src/ONYXKEYS';
import type SCREENS from '@src/SCREENS';
import type * as OnyxTypes from '@src/types/onyx';

type UserTypingEventListenerOnyxProps = {
/** Stores last visited path */
lastVisitedPath?: string;
};

type UserTypingEventListenerProps = UserTypingEventListenerOnyxProps & {
/** The report currently being looked at */
report: OnyxTypes.Report;
};
function UserTypingEventListener({report, lastVisitedPath}: UserTypingEventListenerProps) {
const didSubscribeToReportTypingEvents = useRef(false);
const reportID = report.reportID;
const isFocused = useIsFocused();
const route = useRoute<RouteProp<CentralPaneNavigatorParamList, typeof SCREENS.REPORT>>();
useEffect(() => {
// Ensures the optimistic report is created successfully
tienifr marked this conversation as resolved.
Show resolved Hide resolved
if (route?.params?.reportID !== reportID) {
return;
}

if (isFocused) {
// Ensures subscription event succeeds when the report/workspace room is created optimistically.
// Check if the optimistic `OpenReport` or `AddWorkspaceRoom` has succeeded by confirming
// any `pendingFields.createChat` or `pendingFields.addWorkspaceRoom` fields are set to null.
// Existing reports created will have empty fields for `pendingFields`.
const didCreateReportSuccessfully = !report.pendingFields || (!report.pendingFields.addWorkspaceRoom && !report.pendingFields.createChat);

if (!didSubscribeToReportTypingEvents.current && didCreateReportSuccessfully) {
const interactionTask = InteractionManager.runAfterInteractions(() => {
Report.subscribeToReportTypingEvents(reportID);
didSubscribeToReportTypingEvents.current = true;
});
return () => {
interactionTask.cancel();
};
}
} else {
const topmostReportId = Navigation.getTopmostReportId();

if (topmostReportId !== report.reportID && didSubscribeToReportTypingEvents.current) {
didSubscribeToReportTypingEvents.current = false;
InteractionManager.runAfterInteractions(() => {
Report.unsubscribeFromReportChannel(report.reportID);
});
}
}
}, [isFocused, report.reportID, report.pendingFields, didSubscribeToReportTypingEvents, lastVisitedPath, reportID, route]);
tienifr marked this conversation as resolved.
Show resolved Hide resolved
tienifr marked this conversation as resolved.
Show resolved Hide resolved

return null;
}

UserTypingEventListener.displayName = 'UserTypingEventListener';

export default withOnyx<UserTypingEventListenerProps, UserTypingEventListenerOnyxProps>({
lastVisitedPath: {
key: ONYXKEYS.LAST_VISITED_PATH,
selector: (path) => path ?? '',
},
})(UserTypingEventListener);
Loading