Skip to content

Commit 0f1990c

Browse files
adhorodyskiclaude
andcommitted
extract useReportActionsVisibility hook
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 2aea227 commit 0f1990c

3 files changed

Lines changed: 130 additions & 83 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import {getAllNonDeletedTransactions} from '@libs/MoneyRequestReportUtils';
2+
import {isCreatedAction, isDeletedParentAction, isIOUActionMatchingTransactionList, isReportActionVisible} from '@libs/ReportActionsUtils';
3+
import {isConciergeChatReport} from '@libs/ReportUtils';
4+
import CONST from '@src/CONST';
5+
import ONYXKEYS from '@src/ONYXKEYS';
6+
import type {ReportAction} from '@src/types/onyx';
7+
import useConciergeSidePanelReportActions from './useConciergeSidePanelReportActions';
8+
import useCurrentUserPersonalDetails from './useCurrentUserPersonalDetails';
9+
import useIsInSidePanel from './useIsInSidePanel';
10+
import useLocalize from './useLocalize';
11+
import useNetwork from './useNetwork';
12+
import useOnyx from './useOnyx';
13+
import useSidePanelState from './useSidePanelState';
14+
import useTransactionsAndViolationsForReport from './useTransactionsAndViolationsForReport';
15+
16+
type UseReportActionsVisibilityParams = {
17+
reportID: string | undefined;
18+
reportActions: ReportAction[];
19+
allReportActions: ReportAction[];
20+
canPerformWriteAction: boolean;
21+
hasOlderActions: boolean;
22+
loadOlderChats: (force?: boolean) => void;
23+
};
24+
25+
type UseReportActionsVisibilityResult = {
26+
sortedReportActions: ReportAction[];
27+
sortedVisibleReportActions: ReportAction[];
28+
isConciergeSidePanel: boolean;
29+
showConciergeSidePanelWelcome: boolean;
30+
showFullHistory: boolean;
31+
hasPreviousMessages: boolean;
32+
handleShowPreviousMessages: () => void;
33+
};
34+
35+
function useReportActionsVisibility({
36+
reportID,
37+
reportActions,
38+
allReportActions,
39+
canPerformWriteAction,
40+
hasOlderActions,
41+
loadOlderChats,
42+
}: UseReportActionsVisibilityParams): UseReportActionsVisibilityResult {
43+
const {isOffline} = useNetwork();
44+
const {translate} = useLocalize();
45+
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
46+
47+
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
48+
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
49+
const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS);
50+
51+
const isInSidePanel = useIsInSidePanel();
52+
const isConciergeSidePanel = isInSidePanel && isConciergeChatReport(report, conciergeReportID);
53+
54+
const {sessionStartTime} = useSidePanelState();
55+
56+
const hasUserSentMessage =
57+
isConciergeSidePanel && sessionStartTime
58+
? allReportActions.some((action) => !isCreatedAction(action) && action.actorAccountID === currentUserAccountID && action.created >= sessionStartTime)
59+
: false;
60+
61+
const {transactions: reportTransactions, isLoaded: areTransactionsLoaded} = useTransactionsAndViolationsForReport(reportID);
62+
// When transactions haven't loaded yet, pass undefined to skip IOU filtering entirely
63+
// (undefined = "don't filter" in isIOUActionMatchingTransactionList).
64+
// Once loaded, filter normally — even if transactions is empty (genuinely no transactions).
65+
const reportTransactionIDs = areTransactionsLoaded ? getAllNonDeletedTransactions(reportTransactions, allReportActions ?? []).map((transaction) => transaction.transactionID) : undefined;
66+
67+
const visibleReportActions = reportActions.filter((reportAction) => {
68+
const passesOfflineCheck = isOffline || isDeletedParentAction(reportAction) || reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || reportAction.errors;
69+
70+
if (!passesOfflineCheck) {
71+
return false;
72+
}
73+
74+
const actionReportID = reportAction.reportID ?? reportID;
75+
if (!isReportActionVisible(reportAction, actionReportID, canPerformWriteAction, visibleReportActionsData)) {
76+
return false;
77+
}
78+
79+
if (!isIOUActionMatchingTransactionList(reportAction, reportTransactionIDs)) {
80+
return false;
81+
}
82+
83+
return true;
84+
});
85+
86+
const {filteredVisibleActions, filteredReportActions, showConciergeSidePanelWelcome, showFullHistory, hasPreviousMessages, handleShowPreviousMessages} =
87+
useConciergeSidePanelReportActions({
88+
report,
89+
reportActions,
90+
visibleReportActions,
91+
isConciergeSidePanel,
92+
hasUserSentMessage,
93+
hasOlderActions,
94+
sessionStartTime,
95+
currentUserAccountID,
96+
greetingText: translate('common.concierge.sidePanelGreeting'),
97+
loadOlderChats,
98+
});
99+
100+
return {
101+
sortedReportActions: filteredReportActions,
102+
sortedVisibleReportActions: filteredVisibleActions,
103+
isConciergeSidePanel,
104+
showConciergeSidePanelWelcome,
105+
showFullHistory,
106+
hasPreviousMessages,
107+
handleShowPreviousMessages,
108+
};
109+
}
110+
111+
export default useReportActionsVisibility;

src/hooks/useTransactionsAndViolationsForReport.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function useTransactionsAndViolationsForReport(reportID?: string) {
2323
filteredViolations[transactionViolationKey] = getTransactionViolations(transaction, violations, currentUserDetails.email ?? '', currentUserDetails.accountID, report, policy) ?? [];
2424
}
2525

26-
return {transactions, violations: filteredViolations};
26+
return {transactions, violations: filteredViolations, isLoaded: allReportsTransactionsAndViolations !== undefined};
2727
}
2828

2929
export default useTransactionsAndViolationsForReport;

src/pages/inbox/report/ReportActionsView.tsx

Lines changed: 18 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,20 @@ import {useRoute} from '@react-navigation/native';
22
import React, {useEffect, useMemo, useRef} from 'react';
33
import type {LayoutChangeEvent} from 'react-native';
44
import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView';
5-
import useConciergeSidePanelReportActions from '@hooks/useConciergeSidePanelReportActions';
65
import useCopySelectionHelper from '@hooks/useCopySelectionHelper';
7-
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
8-
import useIsInSidePanel from '@hooks/useIsInSidePanel';
96
import useLoadReportActions from '@hooks/useLoadReportActions';
10-
import useLocalize from '@hooks/useLocalize';
117
import useNetwork from '@hooks/useNetwork';
128
import useOnyx from '@hooks/useOnyx';
139
import useParentReportAction from '@hooks/useParentReportAction';
1410
import usePendingConciergeResponse from '@hooks/usePendingConciergeResponse';
1511
import useReportActionsPagination from '@hooks/useReportActionsPagination';
12+
import useReportActionsVisibility from '@hooks/useReportActionsVisibility';
1613
import useReportIsArchived from '@hooks/useReportIsArchived';
17-
import useSidePanelState from '@hooks/useSidePanelState';
18-
import useTransactionsAndViolationsForReport from '@hooks/useTransactionsAndViolationsForReport';
1914
import {getReportPreviewAction} from '@libs/actions/IOU/MoneyRequestBuilder';
2015
import {updateLoadingInitialReportAction} from '@libs/actions/Report';
21-
import {getAllNonDeletedTransactions} from '@libs/MoneyRequestReportUtils';
22-
import {isCreatedAction, isDeletedParentAction, isIOUActionMatchingTransactionList, isReportActionVisible} from '@libs/ReportActionsUtils';
23-
import {canUserPerformWriteAction, isConciergeChatReport, isReportTransactionThread as isReportTransactionThreadUtil, isUnread} from '@libs/ReportUtils';
16+
import {canUserPerformWriteAction, isReportTransactionThread as isReportTransactionThreadUtil, isUnread} from '@libs/ReportUtils';
2417
import markOpenReportEnd from '@libs/telemetry/markOpenReportEnd';
2518
import type ReportScreenNavigationProps from '@pages/inbox/types';
26-
import CONST from '@src/CONST';
2719
import ONYXKEYS from '@src/ONYXKEYS';
2820
import isLoadingOnyxValue from '@src/types/utils/isLoadingOnyxValue';
2921
import ReportActionsList from './ReportActionsList';
@@ -42,9 +34,7 @@ function ReportActionsView({reportID, onLayout}: ReportActionsViewProps) {
4234
const reportActionIDFromRoute = route?.params?.reportActionID;
4335

4436
useCopySelectionHelper();
45-
const {translate} = useLocalize();
4637
usePendingConciergeResponse(reportID);
47-
const {accountID: currentUserAccountID} = useCurrentUserPersonalDetails();
4838
const {isOffline} = useNetwork();
4939

5040
const [report, reportResult] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`);
@@ -72,39 +62,19 @@ function ReportActionsView({reportID, onLayout}: ReportActionsViewProps) {
7262
const isLoadingInitialReportActions = reportLoadingState?.isLoadingInitialReportActions;
7363
const hasOnceLoadedReportActions = reportLoadingState?.hasOnceLoadedReportActions;
7464

75-
const isInSidePanel = useIsInSidePanel();
76-
const [conciergeReportID] = useOnyx(ONYXKEYS.CONCIERGE_REPORT_ID);
77-
const isConciergeSidePanel = isInSidePanel && isConciergeChatReport(report, conciergeReportID);
78-
79-
const {sessionStartTime} = useSidePanelState();
80-
81-
const hasUserSentMessage = useMemo(() => {
82-
if (!isConciergeSidePanel || !sessionStartTime) {
83-
return false;
84-
}
85-
return allReportActions.some((action) => !isCreatedAction(action) && action.actorAccountID === currentUserAccountID && action.created >= sessionStartTime);
86-
}, [isConciergeSidePanel, allReportActions, currentUserAccountID, sessionStartTime]);
87-
8865
const isReportTransactionThread = isReportTransactionThreadUtil(report);
8966

9067
const isReportArchived = useReportIsArchived(reportID);
9168
const canPerformWriteAction = !!canUserPerformWriteAction(report, isReportArchived);
9269

9370
const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
94-
const [visibleReportActionsData] = useOnyx(ONYXKEYS.DERIVED.VISIBLE_REPORT_ACTIONS);
9571
const reportPreviewAction = useMemo(() => getReportPreviewAction(report?.chatReportID, report?.reportID), [report?.chatReportID, report?.reportID]);
9672
const didLayout = useRef(false);
9773

9874
useEffect(() => {
9975
didLayout.current = false;
10076
}, [reportID]);
10177

102-
const {transactions: reportTransactions} = useTransactionsAndViolationsForReport(reportID);
103-
const reportTransactionIDs = useMemo(
104-
() => getAllNonDeletedTransactions(reportTransactions, allReportActions ?? []).map((transaction) => transaction.transactionID),
105-
[reportTransactions, allReportActions],
106-
);
107-
10878
useEffect(() => {
10979
// When we linked to message - we do not need to wait for initial actions - they already exists
11080
if (!reportActionIDFromRoute || !isOffline) {
@@ -116,35 +86,6 @@ function ReportActionsView({reportID, onLayout}: ReportActionsViewProps) {
11686
// Remount the list when the deep-linked message or unread anchor changes (scroll positioning), or when the report changes.
11787
const listID = [reportID, reportActionIDFromRoute, hasOnceLoadedReportActions ? undefined : oldestUnreadReportAction?.reportActionID].join(':');
11888

119-
const visibleReportActions = useMemo(
120-
() =>
121-
reportActions.filter((reportAction) => {
122-
const passesOfflineCheck =
123-
isOffline || isDeletedParentAction(reportAction) || reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || reportAction.errors;
124-
125-
if (!passesOfflineCheck) {
126-
return false;
127-
}
128-
129-
const actionReportID = reportAction.reportID ?? reportID;
130-
if (!isReportActionVisible(reportAction, actionReportID, canPerformWriteAction, visibleReportActionsData)) {
131-
return false;
132-
}
133-
134-
if (!isIOUActionMatchingTransactionList(reportAction, reportTransactionIDs)) {
135-
return false;
136-
}
137-
138-
return true;
139-
}),
140-
[canPerformWriteAction, isOffline, reportActions, reportID, reportTransactionIDs, visibleReportActionsData],
141-
);
142-
143-
const isSingleExpenseReport = reportPreviewAction?.childMoneyRequestCount === 1;
144-
const isMissingTransactionThreadReportID = !transactionThreadReport?.reportID;
145-
const isReportDataIncomplete = isSingleExpenseReport && isMissingTransactionThreadReportID;
146-
const isMissingReportActions = visibleReportActions.length === 0;
147-
14889
const {loadOlderChats, loadNewerChats} = useLoadReportActions({
14990
reportID,
15091
reportActions,
@@ -154,25 +95,20 @@ function ReportActionsView({reportID, onLayout}: ReportActionsViewProps) {
15495
hasNewerActions,
15596
});
15697

157-
const {
158-
filteredVisibleActions: conciergeSidePanelFilteredVisibleActions,
159-
filteredReportActions: conciergeSidePanelFilteredReportActions,
160-
showConciergeSidePanelWelcome,
161-
showFullHistory,
162-
hasPreviousMessages,
163-
handleShowPreviousMessages,
164-
} = useConciergeSidePanelReportActions({
165-
report,
166-
reportActions,
167-
visibleReportActions,
168-
isConciergeSidePanel,
169-
hasUserSentMessage,
170-
hasOlderActions,
171-
sessionStartTime,
172-
currentUserAccountID,
173-
greetingText: translate('common.concierge.sidePanelGreeting'),
174-
loadOlderChats,
175-
});
98+
const {sortedReportActions, sortedVisibleReportActions, isConciergeSidePanel, showConciergeSidePanelWelcome, showFullHistory, hasPreviousMessages, handleShowPreviousMessages} =
99+
useReportActionsVisibility({
100+
reportID,
101+
reportActions,
102+
allReportActions,
103+
canPerformWriteAction,
104+
hasOlderActions,
105+
loadOlderChats,
106+
});
107+
108+
const isSingleExpenseReport = reportPreviewAction?.childMoneyRequestCount === 1;
109+
const isMissingTransactionThreadReportID = !transactionThreadReport?.reportID;
110+
const isReportDataIncomplete = isSingleExpenseReport && isMissingTransactionThreadReportID;
111+
const isMissingReportActions = sortedVisibleReportActions.length === 0;
176112

177113
/**
178114
* Runs when the FlatList finishes laying out
@@ -244,8 +180,8 @@ function ReportActionsView({reportID, onLayout}: ReportActionsViewProps) {
244180
parentReportAction={parentReportAction}
245181
parentReportActionForTransactionThread={parentReportActionForTransactionThread}
246182
onLayout={recordTimeToMeasureItemLayout}
247-
sortedReportActions={conciergeSidePanelFilteredReportActions}
248-
sortedVisibleReportActions={conciergeSidePanelFilteredVisibleActions}
183+
sortedReportActions={sortedReportActions}
184+
sortedVisibleReportActions={sortedVisibleReportActions}
249185
loadOlderChats={loadOlderChats}
250186
loadNewerChats={loadNewerChats}
251187
hasNewerActions={hasNewerActions}

0 commit comments

Comments
 (0)