@@ -7,6 +7,8 @@ import type {OnyxEntry} from 'react-native-onyx';
77import Animated , { useAnimatedStyle , useSharedValue , withTiming } from 'react-native-reanimated' ;
88import FullPageErrorView from '@components/BlockingViews/FullPageErrorView' ;
99import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView' ;
10+ import type { ActionHandledType } from '@components/ProcessMoneyReportHoldMenu' ;
11+ import ProcessMoneyReportHoldMenu from '@components/ProcessMoneyReportHoldMenu' ;
1012import type { SelectionListHandle } from '@components/SelectionList/types' ;
1113import SearchRowSkeleton from '@components/Skeletons/SearchRowSkeleton' ;
1214import { useWideRHPActions } from '@components/WideRHPContextProvider' ;
@@ -35,7 +37,7 @@ import type {PlatformStackNavigationProp} from '@libs/Navigation/PlatformStackNa
3537import TransitionTracker from '@libs/Navigation/TransitionTracker' ;
3638import { isCreatedTaskReportAction } from '@libs/ReportActionsUtils' ;
3739import { isSplitAction } from '@libs/ReportSecondaryActionUtils' ;
38- import { canEditFieldOfMoneyRequest , canHoldUnholdReportAction , canRejectReportAction , isOneTransactionReport , selectFilteredReportActions } from '@libs/ReportUtils' ;
40+ import { canEditFieldOfMoneyRequest , canHoldUnholdReportAction , canRejectReportAction , getNonHeldAndFullAmount , isOneTransactionReport , selectFilteredReportActions } from '@libs/ReportUtils' ;
3941import { buildCannedSearchQuery , buildSearchQueryString , isDefaultExpensesQuery } from '@libs/SearchQueryUtils' ;
4042import {
4143 createAndOpenSearchTransactionThread ,
@@ -71,7 +73,8 @@ import ONYXKEYS from '@src/ONYXKEYS';
7173import ROUTES from '@src/ROUTES' ;
7274import SCREENS from '@src/SCREENS' ;
7375import { columnsSelector } from '@src/selectors/AdvancedSearchFiltersForm' ;
74- import type { OutstandingReportsByPolicyIDDerivedValue , SaveSearch , Transaction } from '@src/types/onyx' ;
76+ import type { OutstandingReportsByPolicyIDDerivedValue , Report , SaveSearch , Transaction } from '@src/types/onyx' ;
77+ import type { PaymentMethodType } from '@src/types/onyx/OriginalMessage' ;
7578import type SearchResults from '@src/types/onyx/SearchResults' ;
7679import { isEmptyObject } from '@src/types/utils/EmptyObject' ;
7780import arraysEqual from '@src/utils/arraysEqual' ;
@@ -101,6 +104,8 @@ type SearchProps = {
101104 onDestinationVisible ?: ( wasListEmpty : boolean , source : 'focus' | 'layout' ) => void ;
102105} ;
103106
107+ type HoldMenuCallback = ( item : TransactionReportGroupListItemType , requestType : ActionHandledType , paymentType ?: PaymentMethodType ) => void ;
108+
104109// Max time (ms) to keep the optimistic item cache/skeleton alive before
105110// clearing all tracking state. Must be longer than deferredLayoutWrite's
106111// 5s safety timeout so the API.write() has time to apply optimistic data.
@@ -293,6 +298,19 @@ function Search({
293298 const styles = useThemeStyles ( ) ;
294299 const navigation = useNavigation < PlatformStackNavigationProp < SearchFullscreenNavigatorParamList > > ( ) ;
295300 const isFocused = useIsFocused ( ) ;
301+ const [ isHoldMenuVisible , setIsHoldMenuVisible ] = useState ( false ) ;
302+ const [ holdMenuParams , setHoldMenuParams ] = useState < {
303+ chatReport : OnyxEntry < Report > ;
304+ fullAmount : string ;
305+ moneyRequestReport : OnyxEntry < Report > ;
306+ transactionCount : number ;
307+ nonHeldAmount : string ;
308+ requestType : ActionHandledType ;
309+ paymentType ?: PaymentMethodType ;
310+ hasValidNonHeldAmount : boolean ;
311+ hasNoneHeldExpenses : boolean ;
312+ } | null > ( null ) ;
313+
296314 const { markReportIDAsExpense, markReportIDAsMultiTransactionExpense, unmarkReportIDAsMultiTransactionExpense} = useWideRHPActions ( ) ;
297315 const {
298316 currentSearchHash,
@@ -352,6 +370,26 @@ function Search({
352370 selector : savedSearchSelector ,
353371 } ) ;
354372
373+ const handleHoldMenuOpen = useCallback (
374+ ( item : TransactionReportGroupListItemType , requestType : ActionHandledType , paymentType ?: PaymentMethodType ) => {
375+ const chatReport = searchResults ?. data ?. [ `${ ONYXKEYS . COLLECTION . REPORT } ${ item . parentReportID } ` ] ;
376+ const moneyRequestReport = searchResults ?. data ?. [ `${ ONYXKEYS . COLLECTION . REPORT } ${ item . reportID } ` ] ;
377+ const { nonHeldAmount, fullAmount, hasValidNonHeldAmount} = getNonHeldAndFullAmount ( moneyRequestReport , item . allActions ?. includes ( CONST . SEARCH . ACTION_TYPES . PAY ) ?? false ) ;
378+ setHoldMenuParams ( {
379+ chatReport,
380+ moneyRequestReport,
381+ transactionCount : item . transactionCount ?? 0 ,
382+ fullAmount,
383+ requestType,
384+ paymentType,
385+ nonHeldAmount,
386+ hasValidNonHeldAmount,
387+ hasNoneHeldExpenses : item . transactions . some ( ( t ) => ! isOnHold ( t ) ) ,
388+ } ) ;
389+ setIsHoldMenuVisible ( true ) ;
390+ } ,
391+ [ searchResults ?. data ] ,
392+ ) ;
355393 const { convertToDisplayString} = useCurrencyListActions ( ) ;
356394
357395 const validGroupBy = getValidGroupBy ( groupBy ) ;
@@ -1724,18 +1762,33 @@ function Search({
17241762 shouldAnimate = { type === CONST . SEARCH . DATA_TYPES . EXPENSE }
17251763 newTransactions = { newTransactions }
17261764 hasLoadedAllTransactions = { hasLoadedAllTransactions }
1765+ onHoldMenuOpen = { handleHoldMenuOpen }
17271766 policyForMovingExpenses = { policyForMovingExpenses }
17281767 nonPersonalAndWorkspaceCards = { nonPersonalAndWorkspaceCards }
17291768 isActionColumnWide = { isTask || hasDeletedTransaction }
17301769 />
1770+ { isHoldMenuVisible && ! ! holdMenuParams && (
1771+ < ProcessMoneyReportHoldMenu
1772+ isVisible = { isHoldMenuVisible }
1773+ onClose = { ( ) => setIsHoldMenuVisible ( false ) }
1774+ chatReport = { holdMenuParams . chatReport }
1775+ fullAmount = { holdMenuParams . fullAmount }
1776+ moneyRequestReport = { holdMenuParams . moneyRequestReport }
1777+ transactionCount = { holdMenuParams . transactionCount }
1778+ hasNonHeldExpenses = { holdMenuParams ?. hasNoneHeldExpenses }
1779+ nonHeldAmount = { holdMenuParams . hasNoneHeldExpenses && holdMenuParams . hasValidNonHeldAmount ? holdMenuParams . nonHeldAmount : undefined }
1780+ requestType = { holdMenuParams . requestType }
1781+ paymentType = { holdMenuParams . paymentType }
1782+ />
1783+ ) }
17311784 </ Animated . View >
17321785 </ SearchScopeProvider >
17331786 ) ;
17341787}
17351788
17361789Search . displayName = 'Search' ;
17371790
1738- export type { SearchProps } ;
1791+ export type { SearchProps , HoldMenuCallback } ;
17391792const WrappedSearch = Sentry . withProfiler ( Search ) as typeof Search ;
17401793WrappedSearch . displayName = 'Search' ;
17411794
0 commit comments