Skip to content

Commit 1552b9b

Browse files
committed
Merge branch 'main' into fix/65683
2 parents 40dc6ea + 1d3b6b1 commit 1552b9b

14 files changed

Lines changed: 130 additions & 174 deletions

File tree

src/components/AddPlaidBankAccount.tsx

Lines changed: 6 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React, {useCallback, useEffect, useRef, useState} from 'react';
22
import {ActivityIndicator, View} from 'react-native';
33
import type {OnyxEntry} from 'react-native-onyx';
4-
import {withOnyx} from 'react-native-onyx';
54
import useLocalize from '@hooks/useLocalize';
65
import useNetwork from '@hooks/useNetwork';
6+
import useOnyx from '@hooks/useOnyx';
77
import useTheme from '@hooks/useTheme';
88
import useThemeStyles from '@hooks/useThemeStyles';
99
import {handlePlaidError, openPlaidBankAccountSelector, openPlaidBankLogin, setPlaidEvent} from '@libs/actions/BankAccounts';
@@ -22,15 +22,7 @@ import PlaidLink from './PlaidLink';
2222
import RadioButtons from './RadioButtons';
2323
import Text from './Text';
2424

25-
type AddPlaidBankAccountOnyxProps = {
26-
/** If the user has been throttled from Plaid */
27-
isPlaidDisabled: OnyxEntry<boolean>;
28-
29-
/** Plaid SDK token to use to initialize the widget */
30-
plaidLinkToken: OnyxEntry<string>;
31-
};
32-
33-
type AddPlaidBankAccountProps = AddPlaidBankAccountOnyxProps & {
25+
type AddPlaidBankAccountProps = {
3426
/** Contains plaid data */
3527
plaidData: OnyxEntry<PlaidData>;
3628

@@ -71,15 +63,13 @@ type AddPlaidBankAccountProps = AddPlaidBankAccountOnyxProps & {
7163
function AddPlaidBankAccount({
7264
plaidData,
7365
selectedPlaidAccountID = '',
74-
plaidLinkToken,
7566
onExitPlaid = () => {},
7667
onSelect = () => {},
7768
text = '',
7869
receivedRedirectURI,
7970
plaidLinkOAuthToken = '',
8071
bankAccountID = 0,
8172
allowDebit = false,
82-
isPlaidDisabled,
8373
errorText = '',
8474
onInputChange = () => {},
8575
isDisplayedInWalletFlow = false,
@@ -88,12 +78,13 @@ function AddPlaidBankAccount({
8878
const styles = useThemeStyles();
8979
const plaidBankAccounts = plaidData?.bankAccounts ?? [];
9080
const defaultSelectedPlaidAccount = plaidBankAccounts.find((account) => account.plaidAccountID === selectedPlaidAccountID);
91-
const defaultSelectedPlaidAccountID = defaultSelectedPlaidAccount?.plaidAccountID ?? '-1';
81+
const defaultSelectedPlaidAccountID = defaultSelectedPlaidAccount?.plaidAccountID;
9282
const defaultSelectedPlaidAccountMask = plaidBankAccounts.find((account) => account.plaidAccountID === selectedPlaidAccountID)?.mask ?? '';
9383
const subscribedKeyboardShortcuts = useRef<Array<() => void>>([]);
9484
const previousNetworkState = useRef<boolean | undefined>(undefined);
9585
const [selectedPlaidAccountMask, setSelectedPlaidAccountMask] = useState(defaultSelectedPlaidAccountMask);
96-
86+
const [plaidLinkToken] = useOnyx(ONYXKEYS.PLAID_LINK_TOKEN, {canBeMissing: true, initWithStoredValues: false});
87+
const [isPlaidDisabled] = useOnyx(ONYXKEYS.IS_PLAID_DISABLED, {canBeMissing: true});
9788
const {translate} = useLocalize();
9889
const {isOffline} = useNetwork();
9990

@@ -287,12 +278,4 @@ function AddPlaidBankAccount({
287278

288279
AddPlaidBankAccount.displayName = 'AddPlaidBankAccount';
289280

290-
export default withOnyx<AddPlaidBankAccountProps, AddPlaidBankAccountOnyxProps>({
291-
plaidLinkToken: {
292-
key: ONYXKEYS.PLAID_LINK_TOKEN,
293-
initWithStoredValues: false,
294-
},
295-
isPlaidDisabled: {
296-
key: ONYXKEYS.IS_PLAID_DISABLED,
297-
},
298-
})(AddPlaidBankAccount);
281+
export default AddPlaidBankAccount;

src/components/DownloadAppBanner.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React from 'react';
22
import {View} from 'react-native';
3+
import type {LayoutChangeEvent} from 'react-native';
34
import useHasLoggedIntoMobileApp from '@hooks/useHasLoggedIntoMobileApp';
45
import useLocalize from '@hooks/useLocalize';
56
import useThemeStyles from '@hooks/useThemeStyles';
@@ -9,7 +10,11 @@ import ROUTES from '@src/ROUTES';
910
import Button from './Button';
1011
import {ExpensifyMobileApp} from './Icon/Illustrations';
1112

12-
function DownloadAppBanner() {
13+
type DownloadAppBannerProps = {
14+
onLayout?: (e: LayoutChangeEvent) => void;
15+
};
16+
17+
function DownloadAppBanner({onLayout}: DownloadAppBannerProps) {
1318
const styles = useThemeStyles();
1419
const {translate} = useLocalize();
1520
const {hasLoggedIntoMobileApp, isLastMobileAppLoginLoaded} = useHasLoggedIntoMobileApp();
@@ -19,7 +24,10 @@ function DownloadAppBanner() {
1924
}
2025

2126
return (
22-
<View style={[styles.ph2, styles.mb2, styles.stickToBottom]}>
27+
<View
28+
style={[styles.ph2, styles.mb2, styles.stickToBottom, styles.pt2]}
29+
onLayout={onLayout}
30+
>
2331
<BillingBanner
2432
icon={ExpensifyMobileApp}
2533
title={translate('common.getTheApp')}

src/components/MoneyReportHeader.tsx

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,14 @@ function MoneyReportHeader({
188188
{canBeMissing: true},
189189
);
190190

191-
const isExported = isExportedUtils(reportActions);
192-
const integrationNameFromExportMessage = isExported ? getIntegrationNameFromExportMessageUtils(reportActions) : null;
191+
const isExported = useMemo(() => isExportedUtils(reportActions), [reportActions]);
192+
// wrapped in useMemo to improve performance because this is an operation on array
193+
const integrationNameFromExportMessage = useMemo(() => {
194+
if (!isExported) {
195+
return null;
196+
}
197+
return getIntegrationNameFromExportMessageUtils(reportActions);
198+
}, [isExported, reportActions]);
193199

194200
const [reportPreviewAction] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`, {
195201
canBeMissing: true,
@@ -248,7 +254,8 @@ function MoneyReportHeader({
248254
}, [reportPDFFilename, translate]);
249255

250256
// Check if there is pending rter violation in all transactionViolations with given transactionIDs.
251-
const hasAllPendingRTERViolations = allHavePendingRTERViolation(transactions, violations);
257+
// wrapped in useMemo to avoid unnecessary re-renders and for better performance (array operation inside of function)
258+
const hasAllPendingRTERViolations = useMemo(() => allHavePendingRTERViolation(transactions, violations), [transactions, violations]);
252259
// Check if user should see broken connection violation warning.
253260
const shouldShowBrokenConnectionViolation = shouldShowBrokenConnectionViolationForMultipleTransactions(transactionIDs, moneyRequestReport, policy, violations);
254261
const hasOnlyHeldExpenses = hasOnlyHeldExpensesReportUtils(moneyRequestReport?.reportID);

src/components/MoneyRequestConfirmationList.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ function MoneyRequestConfirmationList({
388388
const isMerchantEmpty = useMemo(() => !iouMerchant || isMerchantMissing(transaction), [transaction, iouMerchant]);
389389
const isMerchantRequired = isPolicyExpenseChat && (!isScanRequest || isEditingSplitBill) && shouldShowMerchant;
390390

391-
const isCategoryRequired = !!policy?.requiresCategory;
391+
const isCategoryRequired = !!policy?.requiresCategory && !isTypeInvoice;
392392

393393
useEffect(() => {
394394
if (shouldDisplayFieldError && didConfirmSplit) {

src/components/MoneyRequestReportView/MoneyRequestReportActionsList.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ function MoneyRequestReportActionsList({
126126
const [isVisible, setIsVisible] = useState(Visibility.isVisible);
127127
const isFocused = useIsFocused();
128128
const route = useRoute<PlatformStackRouteProp<ReportsSplitNavigatorParamList, typeof SCREENS.REPORT>>();
129-
const reportTransactionIDs = transactions.map((transaction) => transaction.transactionID);
129+
// wrapped in useMemo to avoid unnecessary re-renders and improve performance
130+
const reportTransactionIDs = useMemo(() => transactions.map((transaction) => transaction.transactionID), [transactions]);
130131
const [chatReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${getNonEmptyStringOnyxID(report?.chatReportID)}`, {canBeMissing: true});
131132

132133
const reportID = report?.reportID;
@@ -551,7 +552,8 @@ function MoneyRequestReportActionsList({
551552
}, []);
552553

553554
const isSelectAllChecked = selectedTransactionIDs.length > 0 && selectedTransactionIDs.length === transactionsWithoutPendingDelete.length;
554-
555+
// Wrapped into useCallback to stabilize children re-renders
556+
const keyExtractor = useCallback((item: OnyxTypes.ReportAction) => item.reportActionID, []);
555557
return (
556558
<View
557559
style={[styles.flex1]}
@@ -638,7 +640,7 @@ function MoneyRequestReportActionsList({
638640
style={styles.overscrollBehaviorContain}
639641
data={visibleReportActions}
640642
renderItem={renderItem}
641-
keyExtractor={(item) => item.reportActionID}
643+
keyExtractor={keyExtractor}
642644
onLayout={recordTimeToMeasureItemLayout}
643645
onEndReached={onEndReached}
644646
onEndReachedThreshold={0.75}

src/libs/ReportUtils.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1849,12 +1849,11 @@ function pushTransactionViolationsOnyxData(
18491849
const hasDependentTags = hasDependentTagsPolicyUtils(optimisticPolicy, policyTagLists);
18501850

18511851
getAllPolicyReports(policyID).forEach((report) => {
1852-
if (!report?.reportID) {
1852+
const isReportAnInvoice = isInvoiceReport(report);
1853+
if (!report?.reportID || isReportAnInvoice) {
18531854
return;
18541855
}
18551856

1856-
const isReportAnInvoice = isInvoiceReport(report);
1857-
18581857
getReportTransactions(report.reportID).forEach((transaction: Transaction) => {
18591858
const transactionViolations = allTransactionViolations?.[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transaction.transactionID}`] ?? [];
18601859

src/libs/actions/IOU.ts

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2379,25 +2379,6 @@ function buildOnyxDataForInvoice(invoiceParams: BuildOnyxDataForInvoiceParams):
23792379
return [optimisticData, successData, failureData];
23802380
}
23812381

2382-
const violationsOnyxData = ViolationsUtils.getViolationsOnyxData(
2383-
transactionParams.transaction,
2384-
[],
2385-
policyParams.policy,
2386-
policyParams.policyTagList ?? {},
2387-
policyParams.policyCategories ?? {},
2388-
hasDependentTags(policyParams.policy, policyParams.policyTagList ?? {}),
2389-
true,
2390-
);
2391-
2392-
if (violationsOnyxData) {
2393-
optimisticData.push(violationsOnyxData);
2394-
failureData.push({
2395-
onyxMethod: Onyx.METHOD.SET,
2396-
key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionParams.transaction.transactionID}`,
2397-
value: [],
2398-
});
2399-
}
2400-
24012382
return [optimisticData, successData, failureData];
24022383
}
24032384

@@ -4329,9 +4310,11 @@ function getUpdateMoneyRequestParams(
43294310
}
43304311
const hasModifiedComment = 'comment' in transactionChanges;
43314312

4313+
const isInvoice = isInvoiceReportReportUtils(iouReport);
43324314
if (
43334315
policy &&
43344316
isPaidGroupPolicy(policy) &&
4317+
!isInvoice &&
43354318
updatedTransaction &&
43364319
(hasModifiedTag || hasModifiedCategory || hasModifiedComment || hasModifiedDistanceRate || hasModifiedAmount || hasModifiedCreated)
43374320
) {
@@ -4343,7 +4326,7 @@ function getUpdateMoneyRequestParams(
43434326
policyTagList ?? {},
43444327
policyCategories ?? {},
43454328
hasDependentTags(policy, policyTagList ?? {}),
4346-
isInvoiceReportReportUtils(iouReport),
4329+
isInvoice,
43474330
);
43484331
optimisticData.push(violationsOnyxData);
43494332
failureData.push({
Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,15 @@
11
import React from 'react';
2-
import type {OnyxEntry} from 'react-native-onyx';
3-
import {withOnyx} from 'react-native-onyx';
4-
import * as LoginUtils from '@libs/LoginUtils';
5-
import ONYXKEYS from '@src/ONYXKEYS';
6-
import type {Session} from '@src/types/onyx';
2+
import {useSession} from '@components/OnyxProvider';
3+
import {isEmailPublicDomain} from '@libs/LoginUtils';
74
import ImTeacherUpdateEmailPage from './ImTeacherUpdateEmailPage';
85
import IntroSchoolPrincipalPage from './IntroSchoolPrincipalPage';
96

10-
type ImTeacherPageOnyxProps = {
11-
session: OnyxEntry<Session>;
12-
};
13-
14-
type ImTeacherPageProps = ImTeacherPageOnyxProps;
15-
16-
function ImTeacherPage(props: ImTeacherPageProps) {
17-
const isLoggedInEmailPublicDomain = LoginUtils.isEmailPublicDomain(props.session?.email ?? '');
7+
function ImTeacherPage() {
8+
const session = useSession();
9+
const isLoggedInEmailPublicDomain = isEmailPublicDomain(session?.email ?? '');
1810
return isLoggedInEmailPublicDomain ? <ImTeacherUpdateEmailPage /> : <IntroSchoolPrincipalPage />;
1911
}
2012

2113
ImTeacherPage.displayName = 'ImTeacherPage';
2214

23-
export default withOnyx<ImTeacherPageProps, ImTeacherPageOnyxProps>({
24-
session: {
25-
key: ONYXKEYS.SESSION,
26-
},
27-
})(ImTeacherPage);
15+
export default ImTeacherPage;

src/pages/home/ReportScreen.tsx

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,8 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
270270
const [currentUserEmail] = useOnyx(ONYXKEYS.SESSION, {selector: (value) => value?.email, canBeMissing: false});
271271
const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP, {canBeMissing: true});
272272
const {reportActions: unfilteredReportActions, linkedAction, sortedAllReportActions, hasNewerActions, hasOlderActions} = usePaginatedReportActions(reportID, reportActionIDFromRoute);
273-
const reportActions = getFilteredReportActionsForReportView(unfilteredReportActions);
273+
// wrapping in useMemo because this is array operation and can cause performance issues
274+
const reportActions = useMemo(() => getFilteredReportActionsForReportView(unfilteredReportActions), [unfilteredReportActions]);
274275
const [childReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${linkedAction?.childReportID}`, {canBeMissing: true});
275276

276277
const [isBannerVisible, setIsBannerVisible] = useState(true);
@@ -300,14 +301,19 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
300301
const {transactions: allReportTransactions} = useTransactionsAndViolationsForReport(reportIDFromRoute);
301302

302303
const reportTransactions = useMemo(() => getAllNonDeletedTransactions(allReportTransactions, reportActions), [allReportTransactions, reportActions]);
303-
const visibleTransactions = reportTransactions?.filter((transaction) => isOffline || transaction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
304-
const reportTransactionIDs = visibleTransactions?.map((transaction) => transaction.transactionID);
304+
// wrapping in useMemo because this is array operation and can cause performance issues
305+
const visibleTransactions = useMemo(
306+
() => reportTransactions?.filter((transaction) => isOffline || transaction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE),
307+
[reportTransactions, isOffline],
308+
);
309+
const reportTransactionIDs = useMemo(() => visibleTransactions?.map((transaction) => transaction.transactionID), [visibleTransactions]);
305310
const transactionThreadReportID = getOneTransactionThreadReportID(report, chatReport, reportActions ?? [], isOffline, reportTransactionIDs);
306311
const [transactionThreadReportActions = getEmptyObject<OnyxTypes.ReportActions>()] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadReportID}`, {
307312
canBeMissing: true,
308313
});
309314
const combinedReportActions = getCombinedReportActions(reportActions, transactionThreadReportID ?? null, Object.values(transactionThreadReportActions));
310315
const lastReportAction = [...combinedReportActions, parentReportAction].find((action) => canEditReportAction(action) && !isMoneyRequestAction(action));
316+
// wrapping in useMemo to stabilize children re-rendering
311317
const policy = policies?.[`${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`];
312318
const isTopMostReportId = currentReportIDValue?.currentReportID === reportIDFromRoute;
313319
const didSubscribeToReportLeavingEvents = useRef(false);
@@ -756,6 +762,12 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
756762
const onComposerFocus = useCallback(() => setIsComposerFocus(true), []);
757763
const onComposerBlur = useCallback(() => setIsComposerFocus(false), []);
758764

765+
// wrapping into useMemo to stabilize children re-renders as reportMetadata is changed frequently
766+
const showReportActionsLoadingState = useMemo(
767+
() => reportMetadata?.isLoadingInitialReportActions && !reportMetadata?.hasOnceLoadedReportActions,
768+
[reportMetadata?.isLoadingInitialReportActions, reportMetadata?.hasOnceLoadedReportActions],
769+
);
770+
759771
// Define here because reportActions are recalculated before mount, allowing data to display faster than useEffect can trigger.
760772
// If we have cached reportActions, they will be shown immediately.
761773
// We aim to display a loader first, then fetch relevant reportActions, and finally show them.
@@ -833,7 +845,7 @@ function ReportScreen({route, navigation}: ReportScreenProps) {
833845
newTransactions={newTransactions}
834846
hasOlderActions={hasOlderActions}
835847
hasNewerActions={hasNewerActions}
836-
showReportActionsLoadingState={reportMetadata?.isLoadingInitialReportActions && !reportMetadata?.hasOnceLoadedReportActions}
848+
showReportActionsLoadingState={showReportActionsLoadingState}
837849
/>
838850
) : null}
839851
{isCurrentReportLoadedFromOnyx ? (

0 commit comments

Comments
 (0)