Skip to content

Commit 8a920ef

Browse files
authored
Merge pull request Expensify#63555 from software-mansion-labs/@szymczak/dont-show-loading-when-created-new-report
2 parents 286d9cb + 7a9444c commit 8a920ef

7 files changed

Lines changed: 50 additions & 27 deletions

File tree

src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ type MoneyRequestReportListProps = {
9494
/** If the report has older actions to load */
9595
hasOlderActions: boolean;
9696

97-
/** Whether report actions are still loading */
98-
isLoadingInitialReportActions?: boolean;
97+
/** Whether report actions are still loading and we load the report for the first time, since the last sign in */
98+
showReportActionsLoadingState?: boolean;
9999
};
100100

101101
function getParentReportAction(parentReportActions: OnyxEntry<OnyxTypes.ReportActions>, parentReportActionID: string | undefined): OnyxEntry<OnyxTypes.ReportAction> {
@@ -113,7 +113,7 @@ function MoneyRequestReportActionsList({
113113
newTransactions,
114114
hasNewerActions,
115115
hasOlderActions,
116-
isLoadingInitialReportActions,
116+
showReportActionsLoadingState,
117117
}: MoneyRequestReportListProps) {
118118
const styles = useThemeStyles();
119119
const {translate} = useLocalize();
@@ -591,7 +591,7 @@ function MoneyRequestReportActionsList({
591591
isActive={isFloatingMessageCounterVisible}
592592
onClick={scrollToBottomAndMarkReportAsRead}
593593
/>
594-
{isEmpty(visibleReportActions) && isEmpty(transactions) && !isLoadingInitialReportActions ? (
594+
{isEmpty(visibleReportActions) && isEmpty(transactions) && !showReportActionsLoadingState ? (
595595
<>
596596
<MoneyRequestViewReportFields
597597
report={report}
@@ -624,7 +624,7 @@ function MoneyRequestReportActionsList({
624624
newTransactions={newTransactions}
625625
reportActions={reportActions}
626626
hasComments={reportHasComments}
627-
isLoadingInitialReportActions={isLoadingInitialReportActions}
627+
isLoadingInitialReportActions={showReportActionsLoadingState}
628628
scrollToNewTransaction={scrollToNewTransaction}
629629
/>
630630
</>
@@ -633,7 +633,7 @@ function MoneyRequestReportActionsList({
633633
onScroll={trackVerticalScrolling}
634634
contentContainerStyle={[shouldUseNarrowLayout ? styles.pt4 : styles.pt2]}
635635
ref={reportScrollManager.ref}
636-
ListEmptyComponent={!isOffline && isLoadingInitialReportActions ? <ReportActionsListLoadingSkeleton /> : undefined} // This skeleton component is only used for loading state, the empty state is handled by SearchMoneyRequestReportEmptyState
636+
ListEmptyComponent={!isOffline && showReportActionsLoadingState ? <ReportActionsListLoadingSkeleton /> : undefined} // This skeleton component is only used for loading state, the empty state is handled by SearchMoneyRequestReportEmptyState
637637
/>
638638
)}
639639
</View>

src/components/MoneyRequestReportView/MoneyRequestReportView.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
1616
import {removeFailedReport} from '@libs/actions/Report';
1717
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
1818
import Log from '@libs/Log';
19-
import {selectAllTransactionsForReport, shouldDisplayReportTableView} from '@libs/MoneyRequestReportUtils';
19+
import {selectAllTransactionsForReport, shouldDisplayReportTableView, shouldWaitForTransactions as shouldWaitForTransactionsUtil} from '@libs/MoneyRequestReportUtils';
2020
import navigationRef from '@libs/Navigation/navigationRef';
2121
import {getFilteredReportActionsForReportView, getOneTransactionThreadReportID, isMoneyRequestAction} from '@libs/ReportActionsUtils';
2222
import {canEditReportAction, getReportOfflinePendingActionAndErrors, isReportTransactionThread} from '@libs/ReportUtils';
@@ -135,14 +135,9 @@ function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayRe
135135
// If true we will use standard `ReportActionsView` to display report data and a special header, anything else is handled via `MoneyRequestReportActionsList`
136136
const isTransactionThreadView = isReportTransactionThread(report);
137137

138-
// Prevent flash by ensuring transaction data is fully loaded before deciding which view to render
138+
// Prevent the empty state flash by ensuring transaction data is fully loaded before deciding which view to render
139139
// We need to wait for both the selector to finish AND ensure we're not in a loading state where transactions could still populate
140-
const isTransactionDataReady = transactions !== undefined;
141-
const isStillLoadingData = !!isLoadingInitialReportActions || !!reportMetadata?.isLoadingOlderReportActions || !!reportMetadata?.isLoadingNewerReportActions;
142-
const shouldWaitForData =
143-
(!isTransactionDataReady || (isStillLoadingData && transactions?.length === 0)) &&
144-
!isTransactionThreadView &&
145-
report?.pendingFields?.createReport !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD;
140+
const shouldWaitForTransactions = shouldWaitForTransactionsUtil(report, transactions, reportMetadata);
146141

147142
const isEmptyTransactionReport = transactions && transactions.length === 0 && transactionThreadReportID === undefined;
148143
const shouldDisplayMoneyRequestActionsList = !!isEmptyTransactionReport || shouldDisplayReportTableView(report, transactions ?? []);
@@ -182,7 +177,7 @@ function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayRe
182177
[backToRoute, isLoadingInitialReportActions, isTransactionThreadView, parentReportAction, policy, report, reportActions, transactionThreadReportID],
183178
);
184179

185-
if (!!(isLoadingInitialReportActions && reportActions.length === 0 && !isOffline) || shouldWaitForData) {
180+
if (!!(isLoadingInitialReportActions && reportActions.length === 0 && !isOffline) || shouldWaitForTransactions) {
186181
return <InitialLoadingSkeleton styles={styles} />;
187182
}
188183

@@ -237,7 +232,7 @@ function MoneyRequestReportView({report, policy, reportMetadata, shouldDisplayRe
237232
reportActions={reportActions}
238233
hasOlderActions={hasOlderActions}
239234
hasNewerActions={hasNewerActions}
240-
isLoadingInitialReportActions={isLoadingInitialReportActions}
235+
showReportActionsLoadingState={isLoadingInitialReportActions && !reportMetadata?.hasOnceLoadedReportActions}
241236
/>
242237
) : (
243238
<ReportActionsView

src/libs/MoneyRequestReportUtils.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
22
import type {ValueOf} from 'type-fest';
33
import CONST from '@src/CONST';
4-
import type {OriginalMessageIOU, Policy, Report, ReportAction, Transaction} from '@src/types/onyx';
4+
import type {OriginalMessageIOU, Policy, Report, ReportAction, ReportMetadata, Transaction} from '@src/types/onyx';
55
import {convertToDisplayString} from './CurrencyUtils';
66
import {getIOUActionForTransactionID, getOriginalMessage, isDeletedParentAction, isMoneyRequestAction} from './ReportActionsUtils';
77
import {
@@ -91,6 +91,18 @@ function shouldDisplayReportTableView(report: OnyxEntry<Report>, transactions: T
9191
return !isReportTransactionThread(report) && !isSingleTransactionReport(report, transactions);
9292
}
9393

94+
function shouldWaitForTransactions(report: OnyxEntry<Report>, transactions: Transaction[] | undefined, reportMetadata: OnyxEntry<ReportMetadata>) {
95+
const isTransactionDataReady = transactions !== undefined;
96+
const isTransactionThreadView = isReportTransactionThread(report);
97+
const isStillLoadingData = !!reportMetadata?.isLoadingInitialReportActions || !!reportMetadata?.isLoadingOlderReportActions || !!reportMetadata?.isLoadingNewerReportActions;
98+
return (
99+
(!isTransactionDataReady || (isStillLoadingData && transactions?.length === 0)) &&
100+
!isTransactionThreadView &&
101+
report?.pendingFields?.createReport !== CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD &&
102+
!reportMetadata?.hasOnceLoadedReportActions
103+
);
104+
}
105+
94106
/**
95107
* Determines the total amount to be displayed based on the selected button type in the IOU Report Preview.
96108
*
@@ -134,4 +146,5 @@ export {
134146
selectAllTransactionsForReport,
135147
isSingleTransactionReport,
136148
shouldDisplayReportTableView,
149+
shouldWaitForTransactions,
137150
};

src/libs/actions/Report.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,7 @@ function openReport(
10231023
onyxMethod: Onyx.METHOD.MERGE,
10241024
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
10251025
value: {
1026+
hasOnceLoadedReportActions: true,
10261027
isLoadingInitialReportActions: false,
10271028
},
10281029
},
@@ -2712,6 +2713,13 @@ function buildNewReportOptimisticData(policy: OnyxEntry<Policy>, reportID: strin
27122713
key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
27132714
value: optimisticReportData,
27142715
},
2716+
{
2717+
onyxMethod: Onyx.METHOD.SET,
2718+
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
2719+
value: {
2720+
hasOnceLoadedReportActions: true,
2721+
},
2722+
},
27152723
{
27162724
onyxMethod: Onyx.METHOD.SET,
27172725
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`,

src/pages/Search/SearchMoneyRequestReportPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function SearchMoneyRequestReportPage({route}: SearchMoneyRequestPageProps) {
3939

4040
const reportIDFromRoute = getNonEmptyStringOnyxID(route.params?.reportID);
4141
const [report] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportIDFromRoute}`, {allowStaleData: true, canBeMissing: true});
42-
const [reportMetadata = defaultReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {canBeMissing: true});
42+
const [reportMetadata = defaultReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {canBeMissing: true, allowStaleData: true});
4343
const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {allowStaleData: true, initialValue: {}, canBeMissing: false});
4444
const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`];
4545
const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: true});

src/pages/home/ReportScreen.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import useViewportOffsetTop from '@hooks/useViewportOffsetTop';
3131
import {hideEmojiPicker} from '@libs/actions/EmojiPickerAction';
3232
import getNonEmptyStringOnyxID from '@libs/getNonEmptyStringOnyxID';
3333
import Log from '@libs/Log';
34-
import {selectAllTransactionsForReport, shouldDisplayReportTableView} from '@libs/MoneyRequestReportUtils';
34+
import {selectAllTransactionsForReport, shouldDisplayReportTableView, shouldWaitForTransactions as shouldWaitForTransactionsUtil} from '@libs/MoneyRequestReportUtils';
3535
import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
3636
import type {PlatformStackScreenProps} from '@libs/Navigation/PlatformStackNavigation/types';
3737
import clearReportNotifications from '@libs/Notification/clearReportNotifications';
@@ -98,6 +98,7 @@ type ReportScreenNavigationProps = PlatformStackScreenProps<ReportsSplitNavigato
9898
type ReportScreenProps = ReportScreenNavigationProps;
9999

100100
const defaultReportMetadata = {
101+
hasOnceLoadedReportActions: false,
101102
isLoadingInitialReportActions: true,
102103
isLoadingOlderReportActions: false,
103104
hasLoadingOlderReportActionsError: false,
@@ -152,7 +153,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
152153
const [userLeavingStatus] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_USER_IS_LEAVING_ROOM}${reportIDFromRoute}`, {initialValue: false, canBeMissing: true});
153154
const [reportOnyx] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${reportIDFromRoute}`, {allowStaleData: true, canBeMissing: true});
154155
const [reportNameValuePairsOnyx] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_NAME_VALUE_PAIRS}${reportIDFromRoute}`, {allowStaleData: true, canBeMissing: true});
155-
const [reportMetadata = defaultReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {canBeMissing: true});
156+
const [reportMetadata = defaultReportMetadata] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportIDFromRoute}`, {canBeMissing: false, allowStaleData: true});
156157
const [policies] = useOnyx(ONYXKEYS.COLLECTION.POLICY, {allowStaleData: true, initialValue: {}, canBeMissing: false});
157158
const [parentReportAction] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${getNonEmptyStringOnyxID(reportOnyx?.parentReportID)}`, {
158159
canEvict: false,
@@ -293,7 +294,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
293294
// OpenReport will be called each time the user scrolls up the report a bit, clicks on report preview, and then goes back.
294295
const isLinkedMessagePageReady = isLinkedMessageAvailable && (reportActions.length - indexOfLinkedMessage >= CONST.REPORT.MIN_INITIAL_REPORT_ACTION_COUNT || doesCreatedActionExists());
295296

296-
const [reportTransactions = []] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {
297+
const [reportTransactions] = useOnyx(ONYXKEYS.COLLECTION.TRANSACTION, {
297298
selector: (allTransactions): OnyxTypes.Transaction[] => selectAllTransactionsForReport(allTransactions, reportIDFromRoute, reportActions),
298299
canBeMissing: false,
299300
});
@@ -307,11 +308,14 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
307308
const didSubscribeToReportLeavingEvents = useRef(false);
308309
const isTransactionThreadView = isReportTransactionThread(report);
309310
const isMoneyRequestOrInvoiceReport = isMoneyRequestReport(report) || isInvoiceReport(report);
311+
// Prevent the empty state flash by ensuring transaction data is fully loaded before deciding which view to render
312+
// We need to wait for both the selector to finish AND ensure we're not in a loading state where transactions could still populate
313+
const shouldWaitForTransactions = shouldWaitForTransactionsUtil(report, reportTransactions, reportMetadata);
310314

311315
const prevTransactions = usePrevious(reportTransactions);
312316

313317
const newTransactions = useMemo(() => {
314-
if (!prevTransactions || reportTransactions.length <= prevTransactions.length) {
318+
if (!reportTransactions || !prevTransactions || reportTransactions.length <= prevTransactions.length) {
315319
return CONST.EMPTY_ARRAY as unknown as OnyxTypes.Transaction[];
316320
}
317321
return reportTransactions.filter((transaction) => !prevTransactions?.some((prevTransaction) => prevTransaction.transactionID === transaction.transactionID));
@@ -765,7 +769,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
765769
}
766770

767771
// If true reports that are considered MoneyRequest | InvoiceReport will get the new report table view
768-
const shouldDisplayMoneyRequestActionsList = isMoneyRequestOrInvoiceReport && shouldDisplayReportTableView(report, reportTransactions);
772+
const shouldDisplayMoneyRequestActionsList = isMoneyRequestOrInvoiceReport && shouldDisplayReportTableView(report, reportTransactions ?? []);
769773

770774
return (
771775
<ActionListContext.Provider value={actionListValue}>
@@ -812,8 +816,8 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
812816
style={[styles.flex1, styles.justifyContentEnd, styles.overflowHidden]}
813817
testID="report-actions-view-wrapper"
814818
>
815-
{!report && <ReportActionsSkeletonView />}
816-
{!!report && !shouldDisplayMoneyRequestActionsList ? (
819+
{(!report || shouldWaitForTransactions) && <ReportActionsSkeletonView />}
820+
{!!report && !shouldDisplayMoneyRequestActionsList && !shouldWaitForTransactions ? (
817821
<ReportActionsView
818822
report={report}
819823
reportActions={reportActions}
@@ -824,7 +828,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
824828
transactionThreadReportID={transactionThreadReportID}
825829
/>
826830
) : null}
827-
{!!report && shouldDisplayMoneyRequestActionsList ? (
831+
{!!report && shouldDisplayMoneyRequestActionsList && !shouldWaitForTransactions ? (
828832
<MoneyRequestReportActionsList
829833
report={report}
830834
policy={policy}
@@ -833,7 +837,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
833837
newTransactions={newTransactions}
834838
hasOlderActions={hasOlderActions}
835839
hasNewerActions={hasNewerActions}
836-
isLoadingInitialReportActions={reportMetadata?.isLoadingInitialReportActions}
840+
showReportActionsLoadingState={reportMetadata?.isLoadingInitialReportActions && !reportMetadata?.hasOnceLoadedReportActions}
837841
/>
838842
) : null}
839843
{isCurrentReportLoadedFromOnyx ? (

src/types/onyx/ReportMetadata.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ type PendingChatMember = {
1414

1515
/** Model of report metadata */
1616
type ReportMetadata = {
17+
/** Whether the user has successfully opened a report at least once, or if it was created by this user */
18+
hasOnceLoadedReportActions?: boolean;
19+
1720
/** Are we loading newer report actions? */
1821
isLoadingNewerReportActions?: boolean;
1922

0 commit comments

Comments
 (0)