-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Add ability to cycle via reports v2 #69221
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
Changes from all commits
ce177bb
ec0c295
242cc99
6b9a22d
d3a7544
774bf8e
58bb1b8
832b0f3
29d7b80
bd60916
ada820a
1333c3e
e27ca61
78aec84
087411b
83bc3f6
d93408a
faaa735
ecefd43
fafe89b
846bff2
3ef0482
d3d7beb
16a8cd3
3ef513c
85472bd
de51bb9
9fa074a
25c31d6
4396c43
828d603
f2e3749
d7aad36
56b6976
55a5ca4
df34147
1c859a1
e5f15c1
65cc90a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -130,6 +130,7 @@ import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar'; | |
| import MoneyReportHeaderStatusBarSkeleton from './MoneyReportHeaderStatusBarSkeleton'; | ||
| import type {MoneyRequestHeaderStatusBarProps} from './MoneyRequestHeaderStatusBar'; | ||
| import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar'; | ||
| import MoneyRequestReportNavigation from './MoneyRequestReportView/MoneyRequestReportNavigation'; | ||
| import type {PopoverMenuItem} from './PopoverMenu'; | ||
| import type {ActionHandledType} from './ProcessMoneyReportHoldMenu'; | ||
| import ProcessMoneyReportHoldMenu from './ProcessMoneyReportHoldMenu'; | ||
|
|
@@ -401,6 +402,8 @@ function MoneyReportHeader({ | |
|
|
||
| const isReportInRHP = route.name === SCREENS.SEARCH.REPORT_RHP; | ||
| const shouldDisplaySearchRouter = !isReportInRHP || isSmallScreenWidth; | ||
| const isReportInSearch = route.name === SCREENS.SEARCH.MONEY_REQUEST_REPORT; | ||
|
|
||
| const existingB2BInvoiceReport = useParticipantsInvoiceReport(activePolicyID, CONST.REPORT.INVOICE_RECEIVER_TYPE.BUSINESS, chatReport?.policyID); | ||
| const confirmPayment = useCallback( | ||
| (type?: PaymentMethodType | undefined, payAsBusiness?: boolean, methodID?: number, paymentMethod?: PaymentMethod) => { | ||
|
|
@@ -456,14 +459,6 @@ function MoneyReportHeader({ | |
| } else { | ||
| startApprovedAnimation(); | ||
| approveMoneyRequest(moneyRequestReport, true); | ||
| if (currentSearchQueryJSON) { | ||
| search({ | ||
| searchKey: currentSearchKey, | ||
| shouldCalculateTotals: true, | ||
| offset: 0, | ||
| queryJSON: currentSearchQueryJSON, | ||
| }); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
|
|
@@ -1251,44 +1246,6 @@ function MoneyReportHeader({ | |
| </KYCWall> | ||
| ); | ||
|
|
||
| const hasOtherItems = | ||
| (shouldShowNextStep && !!optimisticNextStep?.message?.length) || (shouldShowNextStep && !optimisticNextStep && !!isLoadingInitialReportActions && !isOffline) || !!statusBarProps; | ||
|
|
||
| const moreContentUnfiltered = [ | ||
| shouldShowSelectedTransactionsButton && shouldDisplayNarrowVersion && ( | ||
| <View | ||
| style={[styles.dFlex, styles.w100, !hasOtherItems && styles.pb3]} | ||
| key="1" | ||
| > | ||
| <ButtonWithDropdownMenu | ||
| onPress={() => null} | ||
| options={selectedTransactionsOptions} | ||
| customText={translate('workspace.common.selected', {count: selectedTransactionIDs.length})} | ||
| isSplitButton={false} | ||
| shouldAlwaysShowDropdownMenu | ||
| wrapperStyle={styles.w100} | ||
| /> | ||
| </View> | ||
| ), | ||
| shouldShowNextStep && !!optimisticNextStep?.message?.length && ( | ||
| <MoneyReportHeaderStatusBar | ||
| nextStep={optimisticNextStep} | ||
| key="2" | ||
| /> | ||
| ), | ||
| shouldShowNextStep && !optimisticNextStep && !!isLoadingInitialReportActions && !isOffline && <MoneyReportHeaderStatusBarSkeleton key="3" />, | ||
| !!statusBarProps && ( | ||
| <MoneyRequestHeaderStatusBar | ||
| icon={statusBarProps.icon} | ||
| description={statusBarProps.description} | ||
| key="4" | ||
| /> | ||
| ), | ||
| ]; | ||
| const moreContent = moreContentUnfiltered.filter(Boolean); | ||
| const isMoreContentShown = moreContent.length > 0; | ||
| const shouldAddGapToContents = moreContent.length > 1; | ||
|
|
||
| return ( | ||
| <View style={[styles.pt0, styles.borderBottom]}> | ||
| <HeaderWithBackButton | ||
|
|
@@ -1320,14 +1277,44 @@ function MoneyReportHeader({ | |
| </View> | ||
| )} | ||
| </HeaderWithBackButton> | ||
| {shouldDisplayNarrowVersion && !shouldShowSelectedTransactionsButton && ( | ||
| <View style={[styles.flexRow, styles.gap2, styles.pb3, styles.ph5, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}> | ||
| {!!primaryAction && <View style={[styles.flex1]}>{primaryActionsImplementation[primaryAction]}</View>} | ||
| {!!applicableSecondaryActions.length && KYCMoreDropdown} | ||
| </View> | ||
| )} | ||
|
|
||
| {isMoreContentShown && <View style={[styles.dFlex, styles.flexColumn, shouldAddGapToContents && styles.gap3, styles.pb3, styles.ph5]}>{moreContent}</View>} | ||
| {shouldDisplayNarrowVersion && | ||
| (shouldShowSelectedTransactionsButton ? ( | ||
| <View style={[styles.dFlex, styles.w100, styles.ph5]}> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Lack of spacing for the view component caused padding missing between next steps message and selected button for medium screen here |
||
| <ButtonWithDropdownMenu | ||
| onPress={() => null} | ||
| options={selectedTransactionsOptions} | ||
| customText={translate('workspace.common.selected', {count: selectedTransactionIDs.length})} | ||
| isSplitButton={false} | ||
| shouldAlwaysShowDropdownMenu | ||
| wrapperStyle={styles.w100} | ||
| /> | ||
| </View> | ||
| ) : ( | ||
| <View style={[styles.flexRow, styles.gap2, styles.pb3, styles.ph5, styles.w100, styles.alignItemsCenter, styles.justifyContentCenter]}> | ||
| {!!primaryAction && <View style={[styles.flex1]}>{primaryActionsImplementation[primaryAction]}</View>} | ||
| {!!applicableSecondaryActions.length && KYCMoreDropdown} | ||
| </View> | ||
| ))} | ||
|
|
||
| <View style={[styles.flexRow, styles.gap2, styles.justifyContentStart, styles.flexNoWrap, styles.ph5, styles.pb3]}> | ||
| <View style={[styles.flexShrink1, styles.flexGrow1, styles.mnw0, styles.flexWrap, styles.justifyContentCenter]}> | ||
| {shouldShowNextStep && !!optimisticNextStep?.message?.length && <MoneyReportHeaderStatusBar nextStep={optimisticNextStep} />} | ||
| {shouldShowNextStep && !optimisticNextStep && !!isLoadingInitialReportActions && !isOffline && <MoneyReportHeaderStatusBarSkeleton />} | ||
| {!!statusBarProps && ( | ||
| <MoneyRequestHeaderStatusBar | ||
| icon={statusBarProps.icon} | ||
| description={statusBarProps.description} | ||
| /> | ||
| )} | ||
| </View> | ||
| {isReportInSearch && ( | ||
| <MoneyRequestReportNavigation | ||
| reportID={moneyRequestReport?.reportID} | ||
| shouldDisplayNarrowVersion={shouldDisplayNarrowVersion} | ||
| /> | ||
| )} | ||
| </View> | ||
|
|
||
| <LoadingBar shouldShow={shouldShowLoadingBar && shouldUseNarrowLayout} /> | ||
| {isHoldMenuVisible && requestType !== undefined && ( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,135 @@ | ||
| import React, {useEffect} from 'react'; | ||
| import {View} from 'react-native'; | ||
| import PrevNextButtons from '@components/PrevNextButtons'; | ||
| import Text from '@components/Text'; | ||
| import useLocalize from '@hooks/useLocalize'; | ||
| import useOnyx from '@hooks/useOnyx'; | ||
| import useThemeStyles from '@hooks/useThemeStyles'; | ||
| import {selectArchivedReportsIdSet, selectFilteredReportActions} from '@libs/ReportUtils'; | ||
| import {getSections, getSortedSections} from '@libs/SearchUIUtils'; | ||
| import Navigation from '@navigation/Navigation'; | ||
| import {saveLastSearchParams} from '@userActions/ReportNavigation'; | ||
| import {search} from '@userActions/Search'; | ||
| import CONST from '@src/CONST'; | ||
| import ONYXKEYS from '@src/ONYXKEYS'; | ||
|
|
||
| type MoneyRequestReportNavigationProps = { | ||
| reportID?: string; | ||
| shouldDisplayNarrowVersion: boolean; | ||
| }; | ||
|
|
||
| function MoneyRequestReportNavigation({reportID, shouldDisplayNarrowVersion}: MoneyRequestReportNavigationProps) { | ||
| const [lastSearchQuery] = useOnyx(ONYXKEYS.REPORT_NAVIGATION_LAST_SEARCH_QUERY, {canBeMissing: true}); | ||
| const [currentSearchResults] = useOnyx(`${ONYXKEYS.COLLECTION.SNAPSHOT}${lastSearchQuery?.queryJSON?.hash}`, {canBeMissing: true}); | ||
| const [accountID] = useOnyx(ONYXKEYS.SESSION, {canBeMissing: false, selector: (s) => s?.accountID}); | ||
|
|
||
| const {localeCompare, formatPhoneNumber} = useLocalize(); | ||
|
|
||
| const [exportReportActions] = useOnyx(ONYXKEYS.COLLECTION.REPORT_ACTIONS, { | ||
| canEvict: false, | ||
| canBeMissing: true, | ||
| selector: selectFilteredReportActions, | ||
| }); | ||
|
|
||
| const [archivedReportsIdSet = new Set<string>()] = useOnyx(ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS, { | ||
| canBeMissing: true, | ||
| selector: selectArchivedReportsIdSet, | ||
| }); | ||
|
|
||
| const {type, status, sortBy, sortOrder, groupBy} = lastSearchQuery?.queryJSON ?? {}; | ||
| let results: Array<string | undefined> = []; | ||
| if (!!type && !!groupBy && !!currentSearchResults?.data && !!currentSearchResults?.search) { | ||
| const searchData = getSections(type, currentSearchResults.data, accountID, formatPhoneNumber, groupBy, exportReportActions, lastSearchQuery?.searchKey, archivedReportsIdSet); | ||
| results = getSortedSections(type, status ?? '', searchData, localeCompare, sortBy, sortOrder, groupBy).map((value) => value.reportID); | ||
| } | ||
| const allReports = results; | ||
|
|
||
| const currentIndex = allReports.indexOf(reportID); | ||
| const allReportsCount = lastSearchQuery?.previousLengthOfResults ?? 0; | ||
|
|
||
| const hideNextButton = !lastSearchQuery?.hasMoreResults && currentIndex === allReports.length - 1; | ||
| const hidePrevButton = currentIndex === 0; | ||
| const styles = useThemeStyles(); | ||
| const shouldDisplayNavigationArrows = allReports && allReports.length > 1 && currentIndex !== -1 && !!lastSearchQuery?.queryJSON; | ||
|
|
||
| useEffect(() => { | ||
| if (!lastSearchQuery?.queryJSON) { | ||
| return; | ||
| } | ||
|
|
||
| if (lastSearchQuery.allowPostSearchRecount) { | ||
| saveLastSearchParams({ | ||
| ...lastSearchQuery, | ||
| allowPostSearchRecount: false, | ||
| previousLengthOfResults: allReports.length, | ||
| }); | ||
| return; | ||
| } | ||
|
|
||
| if (currentIndex < allReportsCount - 1) { | ||
| return; | ||
| } | ||
|
|
||
| saveLastSearchParams({ | ||
| ...lastSearchQuery, | ||
| previousLengthOfResults: allReports.length, | ||
| }); | ||
| }, [currentIndex, allReportsCount, allReports.length, lastSearchQuery?.queryJSON, lastSearchQuery]); | ||
|
|
||
| const goToReportId = (reportId?: string) => { | ||
| if (!reportId) { | ||
| return; | ||
| } | ||
| Navigation.setParams({ | ||
| reportID: reportId, | ||
| }); | ||
| }; | ||
|
|
||
| const goToNextReport = () => { | ||
| if (currentIndex === -1 || allReports.length === 0 || !lastSearchQuery?.queryJSON) { | ||
| return; | ||
| } | ||
| const threshold = Math.min(allReports.length * 0.75, allReports.length - 2); | ||
|
|
||
| if (currentIndex + 1 >= threshold && lastSearchQuery?.hasMoreResults) { | ||
| const newOffset = (lastSearchQuery.offset ?? 0) + CONST.SEARCH.RESULTS_PAGE_SIZE; | ||
| search({ | ||
| queryJSON: lastSearchQuery.queryJSON, | ||
| offset: newOffset, | ||
| prevReportsLength: allReports.length, | ||
| shouldCalculateTotals: false, | ||
| searchKey: lastSearchQuery.searchKey, | ||
| }); | ||
| } | ||
|
|
||
| const nextIndex = (currentIndex + 1) % allReports.length; | ||
| goToReportId(allReports.at(nextIndex)); | ||
| }; | ||
|
|
||
| const goToPrevReport = () => { | ||
| if (currentIndex === -1 || allReports.length === 0) { | ||
| return; | ||
| } | ||
|
|
||
| const prevIndex = (currentIndex - 1) % allReports.length; | ||
| goToReportId(allReports.at(prevIndex)); | ||
| }; | ||
|
|
||
| return ( | ||
| shouldDisplayNavigationArrows && ( | ||
| <View style={[styles.flexRow, styles.alignItemsCenter, styles.gap2]}> | ||
| {!shouldDisplayNarrowVersion && <Text style={styles.mutedTextLabel}>{`${currentIndex + 1} of ${allReportsCount}`}</Text>} | ||
| <PrevNextButtons | ||
| isPrevButtonDisabled={hidePrevButton} | ||
| isNextButtonDisabled={hideNextButton} | ||
| onNext={goToNextReport} | ||
| onPrevious={goToPrevReport} | ||
| /> | ||
| </View> | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| MoneyRequestReportNavigation.displayName = 'MoneyRequestReportNavigation'; | ||
|
|
||
| export default MoneyRequestReportNavigation; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -47,6 +47,9 @@ type MoneyRequestReportViewProps = { | |
| /** Whether Report footer (that includes Composer) should be displayed */ | ||
| shouldDisplayReportFooter: boolean; | ||
|
|
||
| /** Whether we should wait for the report to sync */ | ||
| shouldWaitForReportSync: boolean; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add the description for this prop |
||
|
|
||
| /** The `backTo` route that should be used when clicking back button */ | ||
| backToRoute: Route | undefined; | ||
| }; | ||
|
|
@@ -86,7 +89,7 @@ function getParentReportAction(parentReportActions: OnyxEntry<OnyxTypes.ReportAc | |
| return parentReportActions[parentReportActionID]; | ||
| } | ||
|
|
||
| function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayReportFooter, backToRoute}: MoneyRequestReportViewProps) { | ||
| function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayReportFooter, backToRoute, shouldWaitForReportSync}: MoneyRequestReportViewProps) { | ||
| const styles = useThemeStyles(); | ||
| const {isOffline} = useNetwork(); | ||
|
|
||
|
|
@@ -110,8 +113,7 @@ function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayRe | |
| const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, reportActions ?? [], isOffline, reportTransactionIDs); | ||
| const isSentMoneyReport = useMemo(() => reportActions.some((action) => isSentMoneyReportAction(action)), [reportActions]); | ||
|
|
||
| const newTransactions = useNewTransactions(reportMetadata?.hasOnceLoadedReportActions, transactions); | ||
|
|
||
| const newTransactions = useNewTransactions(reportMetadata?.hasOnceLoadedReportActions, shouldWaitForReportSync ? [] : transactions); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually we can’t, because this is tied to the Onyx issue in which, during the first render with a new Onyx key, the data returned is still linked to the previous one. |
||
| const [parentReportAction] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(report?.parentReportID)}`, { | ||
| canEvict: false, | ||
| canBeMissing: true, | ||
|
|
@@ -172,7 +174,7 @@ function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayRe | |
| [backToRoute, isLoadingInitialReportActions, isTransactionThreadView, parentReportAction, policy, report, reportActions, transactionThreadReportID], | ||
| ); | ||
|
|
||
| if (!!(isLoadingInitialReportActions && reportActions.length === 0 && !isOffline) || shouldWaitForTransactions) { | ||
| if (!!(isLoadingInitialReportActions && reportActions.length === 0 && !isOffline) || shouldWaitForTransactions || shouldWaitForReportSync) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Coming from #71268:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the absence of this condition was causing some GUI elements to flicker.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any flickers |
||
| return <InitialLoadingSkeleton styles={styles} />; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we remove this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK this is the expected behaviour now, we don't want to reload search after approving report, it should stay there for the whole flow.