Skip to content

Commit c37068b

Browse files
committed
Merge exfy/main
2 parents 07d0758 + 92ac391 commit c37068b

219 files changed

Lines changed: 4534 additions & 2942 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

babel.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ const metro = {
130130
production: {
131131
plugins: [['transform-remove-console', {exclude: ['error', 'warn']}]],
132132
},
133+
test: {
134+
plugins: ['@babel/plugin-transform-dynamic-import'],
135+
},
133136
},
134137
};
135138

contributingGuides/PERFORMANCE.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ Since our codebase is very complex, it results in a large DOM tree rendered for
282282

283283
One of the most common issues is related to modals, popovers, and tooltips — elements that may appear on the screen. The problem is that they are usually present in the DOM tree even when initially invisible. Because of this, the initial render time of a screen may increase, ultimately slowing down the app.
284284

285-
The solution is better control of invisible elements, making sure they are not included in the first render. This can be done, e.g., by a simple `return null`, smart usage of `lazy loading`, the `useTransition` hook, or the `<Deferred />` component.
285+
The solution is better control of invisible elements, making sure they are not included in the first render. This can be done, e.g., by a simple `return null`, smart usage of `lazy loading`, the `useTransition` hook, or the [`<NavigationDeferredMount />`](/src/components/NavigationDeferredMount.tsx) component. `<NavigationDeferredMount />` gates a heavy subtree behind navigation transition completion via `TransitionTracker`, rendering a cheap `placeholder` until the nav animation has finished, then mounting its `children` inside `startTransition` — ideal for heavy subtrees (e.g. report headers, page-level secondary actions) mounted during navigation transitions that pull many `useOnyx` subscriptions or heavy hooks but don't need to be interactive on first render.
286286

287287
Another issue worth mentioning is unnecessary code execution, especially for elements that are never shown on a specific platform. In theory, we separate the logic between platforms by using index.tsx/index.native.tsx files, but sometimes platform-specific logic may slip in, causing unnecessary execution. For example, this may happen when logic specific to a wide layout (applicable only for web) is included.
288288

@@ -294,6 +294,7 @@ Examples:
294294
- [PopoverWithMeasuredContent optimization for mobile](https://github.com/Expensify/App/pull/68223) - returns early to avoid unnecessary calculations
295295
- [Reduce confirm modal initial render count](https://github.com/Expensify/App/pull/67518) - returns early to reduce first load cost
296296
- [Do not render PopoverMenu until it gets opened](https://github.com/Expensify/App/pull/67877) - adds a wrapper to control if `PopoverMenu` should be rendered
297+
- [Defer mount of MoneyReportHeaderSecondaryActions](https://github.com/Expensify/App/pull/88522) - introduces `NavigationDeferredMount` and uses it to defer the "More" dropdown subtree (20+ `useOnyx` subscriptions) until the navigation transition completes
297298

298299
# Proposing Performance Improvements
299300

contributingGuides/STYLE.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -571,9 +571,7 @@ When you change the function id argument type to allow `undefined`, check if it
571571
572572
```diff
573573
function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = false, updatedTransaction, isFromReviewDuplicates = false}: MoneyRequestViewProps) {
574-
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, {
575-
canEvict: false,
576-
});
574+
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`);
577575
- const parentReportAction = parentReportActions?.[report?.parentReportActionID ?? '-1'];
578576
+ const parentReportAction = parentReportActions?.[report?.parentReportActionID];
579577
```

contributingGuides/philosophies/ONYX-DATA-MANAGEMENT.md

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,17 +35,7 @@ Different platforms come with varying storage capacities and Onyx has a way to g
3535

3636
**To flag a key as safe for removal:**
3737
- Add the key to the `evictableKeys` option in `Onyx.init(options)`
38-
- Implement `canEvict` in the Onyx config for each component subscribing to a key
39-
- The key will only be deleted when all subscribers return `true` for `canEvict`
40-
41-
Example:
42-
```js
43-
Onyx.init({
44-
evictableKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
45-
});
46-
47-
const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, {canEvict: !isActiveReport});
48-
```
38+
- A least recently accessed key will only be deleted when an Onyx operation retries after failing.
4939

5040
## Onyx Derived Values
5141

docs/articles/travel/getting-started/Expensify-Travel-Walkthrough.md

Lines changed: 0 additions & 10 deletions
This file was deleted.

docs/redirects.csv

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -963,6 +963,7 @@ https://help.expensify.com/articles/new-expensify/reports-and-expenses/Delete-Ex
963963
https://help.expensify.com/articles/new-expensify/reports-and-expenses/Duplicate-Detection,https://help.expensify.com/articles/new-expensify/reports-and-expenses/How-to-Find-and-Resolve-Flagged-Duplicate-Expenses
964964
https://help.expensify.com/articles/new-expensify/reports-and-expenses/Merging-expenses,https://help.expensify.com/articles/new-expensify/reports-and-expenses/How-to-Merge-Expenses
965965
https://help.expensify.com/articles/new-expensify/reports-and-expenses/How-to-prevent-duplicate-expenses,https://help.expensify.com/articles/new-expensify/reports-and-expenses/Why-Expenses-Duplicate
966+
https://help.expensify.com/articles/travel/getting-started/Expensify-Travel-Walkthrough,https://help.expensify.com/travel/hubs/getting-started/
966967
https://help.expensify.com/articles/new-expensify/connect-credit-cards/Assign-and-Manage-Cards,https://help.expensify.com/articles/new-expensify/connect-credit-cards/Assign-Company-Cards
967968
https://help.expensify.com/articles/new-expensify/connect-credit-cards/Commercial-feeds,https://help.expensify.com/articles/new-expensify/connect-credit-cards/Set-up-a-Commercial-Card-Feed-Connection
968969
https://help.expensify.com/articles/new-expensify/connect-credit-cards/Company-Card-Settings,https://help.expensify.com/articles/new-expensify/connect-credit-cards/Configure-Company-Card-Settings

ios/Podfile.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,7 @@ PODS:
404404
- nanopb/encode (= 3.30910.0)
405405
- nanopb/decode (3.30910.0)
406406
- nanopb/encode (3.30910.0)
407-
- NitroModules (0.29.4):
407+
- NitroModules (0.35.0):
408408
- boost
409409
- DoubleConversion
410410
- fast_float
@@ -3793,7 +3793,7 @@ PODS:
37933793
- SocketRocket
37943794
- Turf
37953795
- Yoga
3796-
- RNNitroSQLite (9.2.0):
3796+
- RNNitroSQLite (9.6.0):
37973797
- boost
37983798
- DoubleConversion
37993799
- fast_float
@@ -4818,7 +4818,7 @@ SPEC CHECKSUMS:
48184818
MapboxMaps: f87023cf0d72b180b40ea0b6fb4b2d7db6b73b71
48194819
MapboxMobileEvents: d044b9edbe0ec7df60f6c2c9634fe9a7f449266b
48204820
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
4821-
NitroModules: 8bffd214aa360baba0f2c5718fe0acff5ef94763
4821+
NitroModules: f8c2cc3025e4550aee15ff77c525622bf98e774a
48224822
NWWebSocket: b4741420f1976e1dff4da3edad00c401e4f1d769
48234823
Onfido: 65454f91d10758193c857fd149417f6efbea84c5
48244824
onfido-react-native-sdk: bb8cfd9198e2e97978461d969497d18b37e45ca7
@@ -4930,7 +4930,7 @@ SPEC CHECKSUMS:
49304930
RNLiveMarkdown: 589e31da57c2cb6d98b37ac68ae8b0b256247172
49314931
RNLocalize: 05e367a873223683f0e268d0af9a8a8e6aed3b26
49324932
rnmapbox-maps: 392ac61c42a9ff01a51d4c2f6775d9131b5951fb
4933-
RNNitroSQLite: fb251387cfbee73b100cd484a3c886fda681b3b5
4933+
RNNitroSQLite: a9b5965d511ed6e99ce903380e64934d043a0d2c
49344934
RNPermissions: 518f0a0c439acc74e2b9937e0e7d29e5031ae949
49354935
RNReactNativeHapticFeedback: 5f1542065f0b24c9252bd8cf3e83bc9c548182e4
49364936
RNReanimated: fbcb7fd8da5b0b088401542c58fb5d266388f1cf

jest/setupAfterEnv.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
import '@testing-library/react-native';
2+
import type {KeyboardEventName} from 'react-native';
3+
import {Keyboard} from 'react-native';
24
import Onyx from 'react-native-onyx';
35
import ONYXKEYS from '@src/ONYXKEYS';
46

57
jest.useRealTimers();
68

9+
// Patch Keyboard.addListener to return a subscription object with .remove() so that
10+
// @react-navigation/bottom-tabs useIsKeyboardShown hook doesn't crash on cleanup.
11+
if (Keyboard && typeof Keyboard.addListener === 'function') {
12+
const originalAddListener = Keyboard.addListener.bind(Keyboard);
13+
Keyboard.addListener = ((event: KeyboardEventName, callback: () => void) => {
14+
const subscription = originalAddListener(event, callback);
15+
if (!subscription || typeof subscription.remove !== 'function') {
16+
return {remove: jest.fn()};
17+
}
18+
return subscription;
19+
}) as typeof Keyboard.addListener;
20+
}
21+
722
// This mock must live in setupAfterEnv (not setupFiles) because @shopify/flash-list/jestSetup,
823
// imported in setup.ts, registers its own measureLayout mock. Placing ours here ensures it
924
// runs after FlashList's setup and takes precedence.

modules/ExpensifyNitroUtils/android/src/main/java/com/margelo/nitro/utils/HybridAppStartTimeModule.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ package com.margelo.nitro.utils
22

33
import android.content.Context
44
import com.margelo.nitro.NitroModules
5+
import androidx.core.content.edit
56

67
class HybridAppStartTimeModule : HybridAppStartTimeModuleSpec() {
78
override val memorySize: Long = 16L
89

9-
override fun recordAppStartTime() {
10+
fun recordAppStartTime() {
1011
val context = NitroModules.applicationContext ?: return
1112
val sharedPreferences = context.getSharedPreferences("AppStartTime", Context.MODE_PRIVATE)
12-
sharedPreferences.edit().putLong("AppStartTime", System.currentTimeMillis()).apply()
13+
sharedPreferences.edit { putLong("AppStartTime", System.currentTimeMillis()) }
1314
}
1415

1516
override val appStartTime: Double

modules/ExpensifyNitroUtils/nitrogen/generated/android/ExpensifyNitroUtils+autolinking.cmake

Lines changed: 8 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)