diff --git a/.eslintrc.js b/.eslintrc.js
index ac4546567833..3c144064eb62 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -46,6 +46,7 @@ module.exports = {
touchables: ['PressableWithoutFeedback', 'PressableWithFeedback'],
},
],
+ curly: 'error',
},
},
{
diff --git a/.github/workflows/deployExpensifyHelp.yml b/.github/workflows/deployExpensifyHelp.yml
index ca7345ef9462..11f4897ab322 100644
--- a/.github/workflows/deployExpensifyHelp.yml
+++ b/.github/workflows/deployExpensifyHelp.yml
@@ -2,10 +2,6 @@
name: Deploy ExpensifyHelp
on:
- # Runs on pushes targeting the default branch
- push:
- branches: ["main"]
-
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
diff --git a/Cloudflare_CA.crt b/Cloudflare_CA.crt
new file mode 100644
index 000000000000..f02f49a951fc
Binary files /dev/null and b/Cloudflare_CA.crt differ
diff --git a/Gemfile.lock b/Gemfile.lock
index 9487e3c45c7a..079b5a5b742b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -9,7 +9,7 @@ GEM
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
- addressable (2.8.3)
+ addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
@@ -19,20 +19,20 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
- aws-partitions (1.646.0)
- aws-sdk-core (3.160.0)
+ aws-partitions (1.824.0)
+ aws-sdk-core (3.181.1)
aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.525.0)
- aws-sigv4 (~> 1.1)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
- aws-sdk-kms (1.58.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-sdk-kms (1.71.0)
+ aws-sdk-core (~> 3, >= 3.177.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.114.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-sdk-s3 (1.134.0)
+ aws-sdk-core (~> 3, >= 3.181.0)
aws-sdk-kms (~> 1)
- aws-sigv4 (~> 1.4)
- aws-sigv4 (1.5.2)
+ aws-sigv4 (~> 1.6)
+ aws-sigv4 (1.6.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
@@ -79,7 +79,7 @@ GEM
highline (~> 2.0.0)
concurrent-ruby (1.2.2)
declarative (0.0.20)
- digest-crc (0.6.4)
+ digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
@@ -88,8 +88,8 @@ GEM
escape (0.0.4)
ethon (0.16.0)
ffi (>= 1.15.0)
- excon (0.93.0)
- faraday (1.10.2)
+ excon (0.103.0)
+ faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -117,8 +117,8 @@ GEM
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
- fastimage (2.2.6)
- fastlane (2.210.1)
+ fastimage (2.2.7)
+ fastlane (2.215.1)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
@@ -139,10 +139,11 @@ GEM
google-apis-playcustomapp_v1 (~> 0.1)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
+ http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
- multipart-post (~> 2.0.0)
+ multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
optparse (~> 0.1.1)
plist (>= 3.1.0, < 4.0.0)
@@ -150,7 +151,7 @@ GEM
security (= 0.1.3)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
- terminal-table (>= 1.4.5, < 2.0.0)
+ terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
@@ -165,9 +166,9 @@ GEM
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
- google-apis-androidpublisher_v3 (0.29.0)
- google-apis-core (>= 0.9.0, < 2.a)
- google-apis-core (0.9.0)
+ google-apis-androidpublisher_v3 (0.49.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-core (0.11.1)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -176,10 +177,10 @@ GEM
retriable (>= 2.0, < 4.a)
rexml
webrick
- google-apis-iamcredentials_v1 (0.15.0)
- google-apis-core (>= 0.9.0, < 2.a)
- google-apis-playcustomapp_v1 (0.11.0)
- google-apis-core (>= 0.9.0, < 2.a)
+ google-apis-iamcredentials_v1 (0.17.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-playcustomapp_v1 (0.13.0)
+ google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-cloud-core (1.6.0)
@@ -187,8 +188,8 @@ GEM
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
- google-cloud-errors (1.3.0)
- google-cloud-storage (1.43.0)
+ google-cloud-errors (1.3.1)
+ google-cloud-storage (1.44.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
@@ -196,10 +197,9 @@ GEM
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- googleauth (1.2.0)
+ googleauth (1.8.0)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
- memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
@@ -209,26 +209,25 @@ GEM
httpclient (2.8.3)
i18n (1.13.0)
concurrent-ruby (~> 1.0)
- jmespath (1.6.1)
+ jmespath (1.6.2)
json (2.6.3)
- jwt (2.5.0)
- memoist (0.16.2)
+ jwt (2.7.1)
mime-types (3.4.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.0218.1)
- mini_magick (4.11.0)
- mini_mime (1.1.2)
+ mini_magick (4.12.0)
+ mini_mime (1.1.5)
minitest (5.18.0)
molinillo (0.8.0)
multi_json (1.15.0)
- multipart-post (2.0.0)
+ multipart-post (2.3.0)
nanaimo (0.3.0)
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
optparse (0.1.1)
os (1.1.4)
- plist (3.6.0)
+ plist (3.7.0)
public_suffix (4.0.7)
rake (13.0.6)
representable (3.2.0)
@@ -236,23 +235,23 @@ GEM
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
- rexml (3.2.5)
+ rexml (3.2.6)
rouge (2.0.7)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
security (0.1.3)
- signet (0.17.0)
+ signet (0.18.0)
addressable (~> 2.8)
faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
- simctl (1.6.8)
+ simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
- terminal-table (1.8.0)
- unicode-display_width (~> 1.1, >= 1.1.1)
+ terminal-table (3.0.2)
+ unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
tty-screen (0.8.1)
@@ -266,8 +265,8 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
- unicode-display_width (1.8.0)
- webrick (1.7.0)
+ unicode-display_width (2.4.2)
+ webrick (1.8.1)
word_wrap (1.0.0)
xcodeproj (1.22.0)
CFPropertyList (>= 2.3.3, < 4.0)
diff --git a/android/app/build.gradle b/android/app/build.gradle
index f957ea7c5854..1e34491b04ad 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -90,8 +90,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001037105
- versionName "1.3.71-5"
+ versionCode 1001037209
+ versionName "1.3.72-9"
}
flavorDimensions "default"
diff --git a/contributingGuides/ACCESSIBILITY.md b/contributingGuides/ACCESSIBILITY.md
new file mode 100644
index 000000000000..b94cbf3087c8
--- /dev/null
+++ b/contributingGuides/ACCESSIBILITY.md
@@ -0,0 +1,47 @@
+# Accessibility of pressable components
+
+### Base Components
+
+- **GenericPressable**: A basic pressable component with generic functionality. It should generally only be used to creating a new, custom pressable components. Avoid using it directly.
+
+- **PressableWithFeedback**: A pressable component that provides standarised visual and haptic feedback upon pressing.
+
+- **PressableWithoutFeedback**: A pressable component without any visual or haptic feedback.
+
+- **PressableWithoutFocus**: A pressable component without visible efect of focus.
+
+- **PressableWithDelayToggle**: A pressable component that briefly disables then re-enables after a short delay upon pressing.
+
+Accessibility props are unified across all platforms.
+
+### Creating accessible flows
+When implementing pressable components, it's essential to create accessible flows to ensure that users with disabilities can efficiently interact with the app.
+
+- ensure that after performing press focus is set on the correct next element - this is especially important for keyboard users who rely on focus to navigate the app. All Pressable components have a `nextFocusRef` prop that can be used to set the next focusable element after the pressable component. This prop accepts a ref to the next focusable element. For example, if you have a button that opens a modal, you can set the next focus to the first focusable element in the modal. This way, when the user presses the button, focus will be set on the first focusable element in the modal, and the user can continue navigating the modal using the keyboard.
+
+- size of any pressable component should be at least 44x44dp. This is the minimum size recommended by Apple and Google for touch targets. If the pressable component is smaller than `44x44dp`, it will be difficult for users with motor disabilities to interact with it. Pressable components have a `autoHitSlop` prop that can be used to automatically increase the size of the pressable component to `44x44dp`. This prop accepts a boolean value. If set to true, the pressable component will automatically increase its touchable size to 44x44dp. If set to false, the pressable component will not increase its size. By default, this prop is set to false.
+
+- ensure that the pressable component has a label and hint. This is especially important for users with visual disabilities who rely on screen readers to navigate the app. All Pressable components have a `accessibilitylabel` prop that can be used to set the label of the pressable component. This prop accepts a string value. All Pressable components also have a `accessibilityHint` prop that can be used to set the hint of the pressable component. This prop accepts a string value. The accessibilityHint prop is optional. If not set, the pressable component will fallback to the accessibilityLabel prop. For example, if you have a button that opens a modal, you can set the accessibilityLabel to "Open modal" and the accessibilityHint to "Opens a modal with more information". This way, when the user focuses on the button, the screen reader will read "Open modal. Opens a modal with more information". This will help the user understand what the button does and what to expect after pressing it.
+
+- the `enableInScreenReaderStates` prop proves invaluable when aiming to enhance the accessibility of clickable elements, particularly when desiring to enlarge the clickable area of a component, such as an entire row. This can be especially useful, for instance, when dealing with tables where only a small portion of a row, like a checkbox, might traditionally trigger an action. By employing this prop, developers can ensure that the entirety of a designated component, in this case a row, is made accessible to users employing screen readers. This creates a more inclusive user experience, allowing individuals relying on screen readers to interact with the component effortlessly. For instance, in a table, using this prop on a row component enables users to click anywhere within the row to trigger an action, significantly improving accessibility and user-friendliness.
+
+- ensure that the pressable component has a role. This is especially important for users with visual disabilities who rely on screen readers to navigate the app. All Pressable components have a `accessibilityRole` prop that can be used to set the role of the pressable component.
+
+### Testing for accessibility
+It's important to test for accessibility to ensure that the created component has accessibility properties set correctly. This can be done using the following tools:
+
+- **iOS**
+For iOS, you can use the `accessibility inspector` app to test for accessibility. You can find it in the Xcode menu under `Xcode > Open Developer Tool > Accessibility Inspector`. This app allows you to inspect the accessibility properties of any element on the screen. You can also use it to simulate different accessibility settings, such as VoiceOver, color blindness, and more. It's a great tool for testing whether created component has accessibility properties set/passed correctly.
+
+- **Android**
+For Android, you can use the [accessibility scanner](https://support.google.com/accessibility/android/answer/6376570) app to test for accessibility. You can find it in the Google Play Store. This app allows you to inspect the accessibility properties of any element on the screen. You can also use it to simulate different accessibility settings, such as TalkBack, color blindness, and more. It's a great tool for testing whether created component has accessibility properties set correctly. The [result of the accessibility scanner](https://support.google.com/accessibility/android/answer/6376559) app has information about content labeling, implementation, touch target size and low contrast
+This tool requires an installed APK to test on.
+
+- **Web/Desktop**
+On Mac, you can use the [VoiceOver](https://www.apple.com/accessibility/mac/vision/) app to test for accessibility. You can find it in the Mac menu under `System Preferences > Accessibility > VoiceOver` or by pressing `Cmd + F5`. This app allows you to inspect the accessibility properties of any element on the screen. You can also use it to simulate different accessibility settings, such as VoiceOver, color blindness, and more. It's a great tool for testing whether created component has accessibility properties set correctly.
+
+
+### Valuable resources
+- [Apple accessibility guidelines](https://developer.apple.com/design/human-interface-guidelines/accessibility/overview/introduction/)
+- [Google accessibility guidelines](https://developer.android.com/guide/topics/ui/accessibility)
+- [Web accessibility guidelines](https://www.w3.org/WAI/standards-guidelines/wcag/)
\ No newline at end of file
diff --git a/contributingGuides/CONTRIBUTING.md b/contributingGuides/CONTRIBUTING.md
index ae2b98ece85b..b97d04b95e10 100644
--- a/contributingGuides/CONTRIBUTING.md
+++ b/contributingGuides/CONTRIBUTING.md
@@ -2,7 +2,7 @@
Welcome! Thanks for checking out the New Expensify app and taking the time to contribute!
## Getting Started
-If you would like to become an Expensify contributor, the first step is to read this document in its entirety. The second step is to review the README guidelines [here](https://github.com/Expensify/App/blob/main/README.md) to understand our coding philosophy and for a general overview of the code repository (i.e. how to run the app locally, testing, storage, our app philosophy, etc). Please read both documents before asking questions, as it may be covered within the documentation.
+If you would like to become an Expensify contributor, the first step is to read this document in its **entirety**. The second step is to review the README guidelines [here](https://github.com/Expensify/App/blob/main/README.md) to understand our coding philosophy and for a general overview of the code repository (i.e. how to run the app locally, testing, storage, our app philosophy, etc). Please read both documents before asking questions, as it may be covered within the documentation.
#### Test Accounts
You can create as many accounts as needed in order to test your changes directly from [the app](https://new.expensify.com/). An initial account can be created when logging in for the first time, and additional accounts can be created by opening the "New Chat" or "Group Chat" pages via the Global Create menu, inputting a valid email or phone number, and tapping the user's avatar.
@@ -47,7 +47,7 @@ Note: if you are hired for an Upwork job and have any job-specific questions, pl
If you've found a vulnerability, please email security@expensify.com with the subject `Vulnerability Report` instead of creating an issue.
## Payment for Contributions
-We hire and pay external contributors via Upwork.com. If you'd like to be paid for contributing or reporting a bug, please create an Upwork account, apply for an available job in [GitHub](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22), and finally apply for the job in Upwork once your proposal gets selected in GitHub. If you think your compensation should be increased for a specific job, you can request a reevaluation by commenting in the Github issue where the Upwork job was posted.
+We hire and pay external contributors via Upwork.com. If you'd like to be paid for contributing or reporting a bug, please create an Upwork account, apply for an available job in [GitHub](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22), and finally apply for the job in Upwork once your proposal gets selected in GitHub. PLease make sure your Upwork profile is **fully verified** before applying, otherwise you run the risk of not being paid. If you think your compensation should be increased for a specific job, you can request a reevaluation by commenting in the Github issue where the Upwork job was posted.
Payment for your contributions and bug reports will be made no less than 7 days after the pull request is deployed to production to allow for [regression](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#regressions) testing. If you have not received payment after 8 days of the PR being deployed to production, and there are no [regressions](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#regressions), please add a comment to the issue mentioning the BugZero team member (Look for the melvin-bot "Triggered auto assignment to... (`Bug`)" to see who this is).
@@ -89,13 +89,13 @@ It’s possible that you found a new bug that we haven’t posted as a job to th
Please follow these steps to propose a job or raise a bug:
1. Check to ensure a GH issue does not already exist for this job in the [New Expensify Issue list](https://github.com/Expensify/App/issues).
-2. Check to ensure the `Bug:` or `Feature Request:` was not already posted in Slack (specifically the #expensify-bugs or #expensify-open-source [Slack channels](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#slack-channels)). Use your best judgement by searching for similar titles and issue descriptions.
+2. Check to ensure the `Bug:` or `Feature Request:` was not already posted in Slack (specifically the #expensify-bugs or #expensify-open-source [Slack channels](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#slack-channels)). Use your best judgement by searching for similar titles, words and issue descriptions.
3. If your bug or new feature matches with an existing issue, please comment on that Slack thread or GitHub issue with your findings if you think it will help solve the issue.
4. If there is no existing GitHub issue or Upwork job, check if the issue is happening on prod (as opposed to only happening on dev)
5. If the issue is just in dev then it means it's a new issue and has not been deployed to production. In this case, you should try to find the offending PR and comment in the issue tied to the PR and ask the assigned users to add the `DeployBlockerCash` label. If you can't find it, follow the reporting instructions in the next item, but note that the issue is a regression only found in dev and not in prod.
-6. If the issue happens in main, staging, or production then report the issue(s) in the #expensify-bugs Slack channel, using the report bug workflow. You can do this by clicking 'Workflow > report Bug', or typing `/Report bug`. View [this guide](https://github.com/Expensify/App/blob/main/contributingGuides/HOW_TO_CREATE_A_PLAN.md) for help creating a plan when proposing a feature request.
+6. If the issue happens in main, staging, or production then report the issue(s) in the #expensify-bugs Slack channel, using the report bug workflow. You can do this by clicking 'Workflow > report Bug', or typing `/Report bug`. View [this guide](https://github.com/Expensify/App/blob/main/contributingGuides/HOW_TO_CREATE_A_PLAN.md) for help creating a plan when proposing a feature request. Please verify the bug's presence on **every** platform mentioned in the bug report template, and confirm this with a screen recording..
- **Important note/reminder**: never share any information pertaining to a customer of Expensify when describing the bug. This includes, and is not limited to, a customer's name, email, and contact information.
-7. The Expensify team will review your job proposal in the appropriate slack channel. If you've provided a quality proposal that we choose to implement, a GitHub issue will be created and your Slack handle will be included in the original post after `Issue reported by:`
+7. The Applause team will review your job proposal in the appropriate slack channel. If you've provided a quality proposal that we choose to implement, a GitHub issue will be created and your Slack handle will be included in the original post after `Issue reported by:`
8. If an external contributor other than yourself is hired to work on the issue, you will also be hired for the same job in Upwork to receive your payout. No additional work is required. If the issue is fixed internally, a dedicated job will be created to hire and pay you after the issue is fixed.
9. Payment will be made 7 days after code is deployed to production if there are no regressions. If a regression is discovered, payment will be issued 7 days after all regressions are fixed.
diff --git a/contributingGuides/STYLE.md b/contributingGuides/STYLE.md
index ce59438a0681..b615104f6aab 100644
--- a/contributingGuides/STYLE.md
+++ b/contributingGuides/STYLE.md
@@ -567,6 +567,28 @@ A `useEffect()` that does not include referenced props or state in its dependenc
There are pros and cons of each, but ultimately we have standardized on using the `function` keyword to align things more with modern React conventions. There are also some minor cognitive overhead benefits in that you don't need to think about adding and removing brackets when encountering an implicit return. The `function` syntax also has the benefit of being able to be hoisted where arrow functions do not.
+## How do I auto-focus a TextInput using `useFocusEffect()`?
+
+```javascript
+const focusTimeoutRef = useRef(null);
+
+useFocusEffect(useCallback(() => {
+ focusTimeoutRef.current = setTimeout(() => textInputRef.current.focus(), CONST.ANIMATED_TRANSITION);
+ return () => {
+ if (!focusTimeoutRef.current) {
+ return;
+ }
+ clearTimeout(focusTimeoutRef.current);
+ };
+}, []));
+```
+
+This works better than using `onTransitionEnd` because -
+1. `onTransitionEnd` is only fired for the top card in the stack, and therefore does not fire on the new top card when popping a card off the stack. For example - pressing the back button to go from the workspace invite page to the workspace members list.
+2. Using `InteractionsManager.runAfterInteractions` with `useFocusEffect` will interrupt an in-progress transition animation.
+
+Note - This is a solution from [this PR](https://github.com/Expensify/App/pull/26415). You can find detailed discussion in comments.
+
# Onyx Best Practices
[Onyx Documentation](https://github.com/expensify/react-native-onyx)
diff --git a/docs/_sass/_search-bar.scss b/docs/_sass/_search-bar.scss
index ce085878af46..a5cc8ae2ff20 100644
--- a/docs/_sass/_search-bar.scss
+++ b/docs/_sass/_search-bar.scss
@@ -23,14 +23,25 @@ $color-gray-label: $color-gray-label;
#sidebar-search {
background-color: $color-appBG;
width: 375px;
- height: 100vh;
position: fixed;
- display: block;
+ display: flex;
+ flex-direction: column;
+ bottom: 0;
top: 0;
right: 0;
z-index: 2;
}
+#sidebar-search > div:last-child {
+ flex-grow: 1;
+ overflow-y: auto;
+ -ms-overflow-style: none;
+ scrollbar-width: none;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+}
+
@media only screen and (max-width: $breakpoint-tablet) {
#sidebar-search {
width: 100%;
@@ -156,10 +167,6 @@ label.search-label {
background-color: $color-appBG;
border: $color-appBG;
font-family: "ExpensifyNeue", "Helvetica Neue", "Helvetica", Arial, sans-serif !important;
- max-height: 80vh;
- overflow-y: scroll;
- -ms-overflow-style: none;
- scrollbar-width: none;
}
/* Hide the scrollbar */
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index ecec05f1cec1..c7d0f2f4f0f5 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -67,6 +67,8 @@ platform :android do
desc "Build and upload app to Google Play"
lane :beta do
ENV["ENVFILE"]=".env.production"
+ # Google is very unreliable, so we retry a few times
+ ENV["SUPPLY_UPLOAD_MAX_RETRIES"]="5"
gradle(
project_dir: './android',
@@ -86,6 +88,8 @@ platform :android do
desc "Deploy app to Google Play production"
lane :production do
+ # Google is very unreliable, so we retry a few times
+ ENV["SUPPLY_UPLOAD_MAX_RETRIES"]="5"
google_play_track_version_codes(
package_name: "com.expensify.chat",
json_key: './android/app/android-fastlane-json-key.json',
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 07e1cfae80ac..441bd2feab92 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.3.71
+ 1.3.72
CFBundleSignature
????
CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.3.71.5
+ 1.3.72.9
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 49d12cf93594..27273c7f3866 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.3.71
+ 1.3.72
CFBundleSignature
????
CFBundleVersion
- 1.3.71.5
+ 1.3.72.9
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index aeb1887223cd..51b9f6af0e21 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -31,14 +31,14 @@ PODS:
- React-Core
- CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6)
- - FBLazyVector (0.72.3)
- - FBReactNativeSpec (0.72.3):
+ - FBLazyVector (0.72.4)
+ - FBReactNativeSpec (0.72.4):
- RCT-Folly (= 2021.07.22.00)
- - RCTRequired (= 0.72.3)
- - RCTTypeSafety (= 0.72.3)
- - React-Core (= 0.72.3)
- - React-jsi (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
+ - RCTRequired (= 0.72.4)
+ - RCTTypeSafety (= 0.72.4)
+ - React-Core (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
- Firebase/Analytics (8.8.0):
- Firebase/Core
- Firebase/Core (8.8.0):
@@ -220,9 +220,9 @@ PODS:
- AppAuth/Core (~> 1.6)
- GTMSessionFetcher/Core (< 4.0, >= 1.5)
- GTMSessionFetcher/Core (3.1.1)
- - hermes-engine (0.72.3):
- - hermes-engine/Pre-built (= 0.72.3)
- - hermes-engine/Pre-built (0.72.3)
+ - hermes-engine (0.72.4):
+ - hermes-engine/Pre-built (= 0.72.4)
+ - hermes-engine/Pre-built (0.72.4)
- libevent (2.1.12)
- libwebp (1.2.4):
- libwebp/demux (= 1.2.4)
@@ -283,26 +283,26 @@ PODS:
- fmt (~> 6.2.1)
- glog
- libevent
- - RCTRequired (0.72.3)
- - RCTTypeSafety (0.72.3):
- - FBLazyVector (= 0.72.3)
- - RCTRequired (= 0.72.3)
- - React-Core (= 0.72.3)
- - React (0.72.3):
- - React-Core (= 0.72.3)
- - React-Core/DevSupport (= 0.72.3)
- - React-Core/RCTWebSocket (= 0.72.3)
- - React-RCTActionSheet (= 0.72.3)
- - React-RCTAnimation (= 0.72.3)
- - React-RCTBlob (= 0.72.3)
- - React-RCTImage (= 0.72.3)
- - React-RCTLinking (= 0.72.3)
- - React-RCTNetwork (= 0.72.3)
- - React-RCTSettings (= 0.72.3)
- - React-RCTText (= 0.72.3)
- - React-RCTVibration (= 0.72.3)
- - React-callinvoker (0.72.3)
- - React-Codegen (0.72.3):
+ - RCTRequired (0.72.4)
+ - RCTTypeSafety (0.72.4):
+ - FBLazyVector (= 0.72.4)
+ - RCTRequired (= 0.72.4)
+ - React-Core (= 0.72.4)
+ - React (0.72.4):
+ - React-Core (= 0.72.4)
+ - React-Core/DevSupport (= 0.72.4)
+ - React-Core/RCTWebSocket (= 0.72.4)
+ - React-RCTActionSheet (= 0.72.4)
+ - React-RCTAnimation (= 0.72.4)
+ - React-RCTBlob (= 0.72.4)
+ - React-RCTImage (= 0.72.4)
+ - React-RCTLinking (= 0.72.4)
+ - React-RCTNetwork (= 0.72.4)
+ - React-RCTSettings (= 0.72.4)
+ - React-RCTText (= 0.72.4)
+ - React-RCTVibration (= 0.72.4)
+ - React-callinvoker (0.72.4)
+ - React-Codegen (0.72.4):
- DoubleConversion
- FBReactNativeSpec
- glog
@@ -317,11 +317,11 @@ PODS:
- React-rncore
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - React-Core (0.72.3):
+ - React-Core (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-Core/Default (= 0.72.3)
+ - React-Core/Default (= 0.72.4)
- React-cxxreact
- React-hermes
- React-jsi
@@ -331,7 +331,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/CoreModulesHeaders (0.72.3):
+ - React-Core/CoreModulesHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -345,7 +345,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/Default (0.72.3):
+ - React-Core/Default (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -358,23 +358,23 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/DevSupport (0.72.3):
+ - React-Core/DevSupport (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-Core/Default (= 0.72.3)
- - React-Core/RCTWebSocket (= 0.72.3)
+ - React-Core/Default (= 0.72.4)
+ - React-Core/RCTWebSocket (= 0.72.4)
- React-cxxreact
- React-hermes
- React-jsi
- React-jsiexecutor
- - React-jsinspector (= 0.72.3)
+ - React-jsinspector (= 0.72.4)
- React-perflogger
- React-runtimeexecutor
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTActionSheetHeaders (0.72.3):
+ - React-Core/RCTActionSheetHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -388,7 +388,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTAnimationHeaders (0.72.3):
+ - React-Core/RCTAnimationHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -402,7 +402,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTBlobHeaders (0.72.3):
+ - React-Core/RCTBlobHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -416,7 +416,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTImageHeaders (0.72.3):
+ - React-Core/RCTImageHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -430,7 +430,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTLinkingHeaders (0.72.3):
+ - React-Core/RCTLinkingHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -444,7 +444,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTNetworkHeaders (0.72.3):
+ - React-Core/RCTNetworkHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -458,7 +458,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTSettingsHeaders (0.72.3):
+ - React-Core/RCTSettingsHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -472,7 +472,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTTextHeaders (0.72.3):
+ - React-Core/RCTTextHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -486,7 +486,7 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTVibrationHeaders (0.72.3):
+ - React-Core/RCTVibrationHeaders (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -500,11 +500,11 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-Core/RCTWebSocket (0.72.3):
+ - React-Core/RCTWebSocket (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-Core/Default (= 0.72.3)
+ - React-Core/Default (= 0.72.4)
- React-cxxreact
- React-hermes
- React-jsi
@@ -514,57 +514,57 @@ PODS:
- React-utils
- SocketRocket (= 0.6.1)
- Yoga
- - React-CoreModules (0.72.3):
+ - React-CoreModules (0.72.4):
- RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.3)
- - React-Codegen (= 0.72.3)
- - React-Core/CoreModulesHeaders (= 0.72.3)
- - React-jsi (= 0.72.3)
+ - RCTTypeSafety (= 0.72.4)
+ - React-Codegen (= 0.72.4)
+ - React-Core/CoreModulesHeaders (= 0.72.4)
+ - React-jsi (= 0.72.4)
- React-RCTBlob
- - React-RCTImage (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
+ - React-RCTImage (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
- SocketRocket (= 0.6.1)
- - React-cxxreact (0.72.3):
+ - React-cxxreact (0.72.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-callinvoker (= 0.72.3)
- - React-debug (= 0.72.3)
- - React-jsi (= 0.72.3)
- - React-jsinspector (= 0.72.3)
- - React-logger (= 0.72.3)
- - React-perflogger (= 0.72.3)
- - React-runtimeexecutor (= 0.72.3)
- - React-debug (0.72.3)
- - React-hermes (0.72.3):
+ - React-callinvoker (= 0.72.4)
+ - React-debug (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - React-jsinspector (= 0.72.4)
+ - React-logger (= 0.72.4)
+ - React-perflogger (= 0.72.4)
+ - React-runtimeexecutor (= 0.72.4)
+ - React-debug (0.72.4)
+ - React-hermes (0.72.4):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- RCT-Folly/Futures (= 2021.07.22.00)
- - React-cxxreact (= 0.72.3)
+ - React-cxxreact (= 0.72.4)
- React-jsi
- - React-jsiexecutor (= 0.72.3)
- - React-jsinspector (= 0.72.3)
- - React-perflogger (= 0.72.3)
- - React-jsi (0.72.3):
+ - React-jsiexecutor (= 0.72.4)
+ - React-jsinspector (= 0.72.4)
+ - React-perflogger (= 0.72.4)
+ - React-jsi (0.72.4):
- boost (= 1.76.0)
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-jsiexecutor (0.72.3):
+ - React-jsiexecutor (0.72.4):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-cxxreact (= 0.72.3)
- - React-jsi (= 0.72.3)
- - React-perflogger (= 0.72.3)
- - React-jsinspector (0.72.3)
- - React-logger (0.72.3):
+ - React-cxxreact (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - React-perflogger (= 0.72.4)
+ - React-jsinspector (0.72.4)
+ - React-logger (0.72.4):
- glog
- react-native-airship (15.2.6):
- AirshipFrameworkProxy (= 2.0.8)
@@ -593,7 +593,7 @@ PODS:
- React-Core
- react-native-pdf (6.7.1):
- React-Core
- - react-native-performance (4.0.0):
+ - react-native-performance (5.1.0):
- React-Core
- react-native-plaid-link-sdk (10.0.0):
- Plaid (~> 4.1.0)
@@ -614,7 +614,7 @@ PODS:
- React-Core
- react-native-webview (11.23.0):
- React-Core
- - React-NativeModulesApple (0.72.3):
+ - React-NativeModulesApple (0.72.4):
- hermes-engine
- React-callinvoker
- React-Core
@@ -623,17 +623,17 @@ PODS:
- React-runtimeexecutor
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - React-perflogger (0.72.3)
- - React-RCTActionSheet (0.72.3):
- - React-Core/RCTActionSheetHeaders (= 0.72.3)
- - React-RCTAnimation (0.72.3):
+ - React-perflogger (0.72.4)
+ - React-RCTActionSheet (0.72.4):
+ - React-Core/RCTActionSheetHeaders (= 0.72.4)
+ - React-RCTAnimation (0.72.4):
- RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.3)
- - React-Codegen (= 0.72.3)
- - React-Core/RCTAnimationHeaders (= 0.72.3)
- - React-jsi (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
- - React-RCTAppDelegate (0.72.3):
+ - RCTTypeSafety (= 0.72.4)
+ - React-Codegen (= 0.72.4)
+ - React-Core/RCTAnimationHeaders (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-RCTAppDelegate (0.72.4):
- RCT-Folly
- RCTRequired
- RCTTypeSafety
@@ -645,54 +645,54 @@ PODS:
- React-RCTNetwork
- React-runtimescheduler
- ReactCommon/turbomodule/core
- - React-RCTBlob (0.72.3):
+ - React-RCTBlob (0.72.4):
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-Codegen (= 0.72.3)
- - React-Core/RCTBlobHeaders (= 0.72.3)
- - React-Core/RCTWebSocket (= 0.72.3)
- - React-jsi (= 0.72.3)
- - React-RCTNetwork (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
- - React-RCTImage (0.72.3):
+ - React-Codegen (= 0.72.4)
+ - React-Core/RCTBlobHeaders (= 0.72.4)
+ - React-Core/RCTWebSocket (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - React-RCTNetwork (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-RCTImage (0.72.4):
- RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.3)
- - React-Codegen (= 0.72.3)
- - React-Core/RCTImageHeaders (= 0.72.3)
- - React-jsi (= 0.72.3)
- - React-RCTNetwork (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
- - React-RCTLinking (0.72.3):
- - React-Codegen (= 0.72.3)
- - React-Core/RCTLinkingHeaders (= 0.72.3)
- - React-jsi (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
- - React-RCTNetwork (0.72.3):
+ - RCTTypeSafety (= 0.72.4)
+ - React-Codegen (= 0.72.4)
+ - React-Core/RCTImageHeaders (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - React-RCTNetwork (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-RCTLinking (0.72.4):
+ - React-Codegen (= 0.72.4)
+ - React-Core/RCTLinkingHeaders (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-RCTNetwork (0.72.4):
- RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.3)
- - React-Codegen (= 0.72.3)
- - React-Core/RCTNetworkHeaders (= 0.72.3)
- - React-jsi (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
- - React-RCTSettings (0.72.3):
+ - RCTTypeSafety (= 0.72.4)
+ - React-Codegen (= 0.72.4)
+ - React-Core/RCTNetworkHeaders (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-RCTSettings (0.72.4):
- RCT-Folly (= 2021.07.22.00)
- - RCTTypeSafety (= 0.72.3)
- - React-Codegen (= 0.72.3)
- - React-Core/RCTSettingsHeaders (= 0.72.3)
- - React-jsi (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
- - React-RCTText (0.72.3):
- - React-Core/RCTTextHeaders (= 0.72.3)
- - React-RCTVibration (0.72.3):
+ - RCTTypeSafety (= 0.72.4)
+ - React-Codegen (= 0.72.4)
+ - React-Core/RCTSettingsHeaders (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-RCTText (0.72.4):
+ - React-Core/RCTTextHeaders (= 0.72.4)
+ - React-RCTVibration (0.72.4):
- RCT-Folly (= 2021.07.22.00)
- - React-Codegen (= 0.72.3)
- - React-Core/RCTVibrationHeaders (= 0.72.3)
- - React-jsi (= 0.72.3)
- - ReactCommon/turbomodule/core (= 0.72.3)
- - React-rncore (0.72.3)
- - React-runtimeexecutor (0.72.3):
- - React-jsi (= 0.72.3)
- - React-runtimescheduler (0.72.3):
+ - React-Codegen (= 0.72.4)
+ - React-Core/RCTVibrationHeaders (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - ReactCommon/turbomodule/core (= 0.72.4)
+ - React-rncore (0.72.4)
+ - React-runtimeexecutor (0.72.4):
+ - React-jsi (= 0.72.4)
+ - React-runtimescheduler (0.72.4):
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
@@ -700,30 +700,30 @@ PODS:
- React-debug
- React-jsi
- React-runtimeexecutor
- - React-utils (0.72.3):
+ - React-utils (0.72.4):
- glog
- RCT-Folly (= 2021.07.22.00)
- React-debug
- - ReactCommon/turbomodule/bridging (0.72.3):
+ - ReactCommon/turbomodule/bridging (0.72.4):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-callinvoker (= 0.72.3)
- - React-cxxreact (= 0.72.3)
- - React-jsi (= 0.72.3)
- - React-logger (= 0.72.3)
- - React-perflogger (= 0.72.3)
- - ReactCommon/turbomodule/core (0.72.3):
+ - React-callinvoker (= 0.72.4)
+ - React-cxxreact (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - React-logger (= 0.72.4)
+ - React-perflogger (= 0.72.4)
+ - ReactCommon/turbomodule/core (0.72.4):
- DoubleConversion
- glog
- hermes-engine
- RCT-Folly (= 2021.07.22.00)
- - React-callinvoker (= 0.72.3)
- - React-cxxreact (= 0.72.3)
- - React-jsi (= 0.72.3)
- - React-logger (= 0.72.3)
- - React-perflogger (= 0.72.3)
+ - React-callinvoker (= 0.72.4)
+ - React-cxxreact (= 0.72.4)
+ - React-jsi (= 0.72.4)
+ - React-logger (= 0.72.4)
+ - React-perflogger (= 0.72.4)
- RNAppleAuthentication (2.2.2):
- React-Core
- RNCAsyncStorage (1.17.11):
@@ -815,7 +815,7 @@ PODS:
- RNScreens (3.21.0):
- React-Core
- React-RCTImage
- - RNSVG (13.9.0):
+ - RNSVG (13.13.0):
- React-Core
- SDWebImage (5.11.1):
- SDWebImage/Core (= 5.11.1)
@@ -1010,7 +1010,7 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
hermes-engine:
:podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec"
- :tag: hermes-2023-03-20-RNv0.72.0-49794cfc7c81fb8f69fd60c3bbf85a7480cc5a77
+ :tag: hermes-2023-08-07-RNv0.72.4-813b2def12bc9df02654b3e3653ae4a68d0572e0
lottie-react-native:
:path: "../node_modules/lottie-react-native"
onfido-react-native-sdk:
@@ -1182,8 +1182,8 @@ SPEC CHECKSUMS:
BVLinearGradient: 421743791a59d259aec53f4c58793aad031da2ca
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
- FBLazyVector: 4cce221dd782d3ff7c4172167bba09d58af67ccb
- FBReactNativeSpec: c6bd9e179757b3c0ecf815864fae8032377903ef
+ FBLazyVector: 5d4a3b7f411219a45a6d952f77d2c0a6c9989da5
+ FBReactNativeSpec: 3fc2d478e1c4b08276f9dd9128f80ec6d5d85c1f
Firebase: 629510f1a9ddb235f3a7c5c8ceb23ba887f0f814
FirebaseABTesting: 10cbce8db9985ae2e3847ea44e9947dd18f94e10
FirebaseAnalytics: 5506ea8b867d8423485a84b4cd612d279f7b0b8a
@@ -1209,7 +1209,7 @@ SPEC CHECKSUMS:
GoogleUtilities: 9aa0ad5a7bc171f8bae016300bfcfa3fb8425749
GTMAppAuth: 99fb010047ba3973b7026e45393f51f27ab965ae
GTMSessionFetcher: e8647203b65cee28c5f73d0f473d096653945e72
- hermes-engine: 10fbd3f62405c41ea07e71973ea61e1878d07322
+ hermes-engine: 81191603c4eaa01f5e4ae5737a9efcf64756c7b2
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
lottie-ios: 8f97d3271e155c2d688875c29cd3c74908aef5f8
@@ -1229,20 +1229,20 @@ SPEC CHECKSUMS:
Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
- RCTRequired: a2faf4bad4e438ca37b2040cb8f7799baa065c18
- RCTTypeSafety: cb09f3e4747b6d18331a15eb05271de7441ca0b3
- React: 13109005b5353095c052f26af37413340ccf7a5d
- React-callinvoker: c8c87bce983aa499c13cb06d4447c025a35274d6
- React-Codegen: 712d523524d89d71f1cf7cc624854941be983c4d
- React-Core: 688f88b7f3a3d30b4848036223f8b07102c687e5
- React-CoreModules: 63c063a3ade8fb3b1bec5fd9a50f17b0421558c6
- React-cxxreact: 37765b4975541105b2a3322a4b473417c158c869
- React-debug: 51f11ef8db14b47f24e71c42a4916d4192972156
- React-hermes: 935ae71fb3d7654e947beba8498835cd5e479707
- React-jsi: ec628dc7a15ffea969f237b0ea6d2fde212b19dd
- React-jsiexecutor: 59d1eb03af7d30b7d66589c410f13151271e8006
- React-jsinspector: b511447170f561157547bc0bef3f169663860be7
- React-logger: c5b527272d5f22eaa09bb3c3a690fee8f237ae95
+ RCTRequired: c0569ecc035894e4a68baecb30fe6a7ea6e399f9
+ RCTTypeSafety: e90354072c21236e0bcf1699011e39acd25fea2f
+ React: a1be3c6dc0a6e949ccd3e659781aa47bbae1868f
+ React-callinvoker: 1020b33f6cb1a1824f9ca2a86609fbce2a73c6ed
+ React-Codegen: a0a26badf098d4a779acda922caf74f6ecabed28
+ React-Core: 52075b80f10c26f62219d7b5d13d7d8089f027b3
+ React-CoreModules: 21abab85d7ad9038ce2b1c33d39e3baaf7dc9244
+ React-cxxreact: 4ad1cc861e32fb533dad6ff7a4ea25680fa1c994
+ React-debug: 17366a3d5c5d2f5fc04f09101a4af38cb42b54ae
+ React-hermes: 37377d0a56aa0cf55c65248271866ce3268cde3f
+ React-jsi: 6de8b0ccc6b765b58e4eee9ee38049dbeaf5c221
+ React-jsiexecutor: c7f826e40fa9cab5d37cab6130b1af237332b594
+ React-jsinspector: aaed4cf551c4a1c98092436518c2d267b13a673f
+ React-logger: da1ebe05ae06eb6db4b162202faeafac4b435e77
react-native-airship: 5d19f4ba303481cf4101ff9dee9249ef6a8a6b64
react-native-blob-util: 99f4d79189252f597fe0d810c57a3733b1b1dea6
react-native-cameraroll: 8ffb0af7a5e5de225fd667610e2979fc1f0c2151
@@ -1255,30 +1255,30 @@ SPEC CHECKSUMS:
react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df
react-native-pdf: 7c0e91ada997bac8bac3bb5bea5b6b81f5a3caae
- react-native-performance: 224bd53e6a835fda4353302cf891d088a0af7406
+ react-native-performance: cef2b618d47b277fb5c3280b81a3aad1e72f2886
react-native-plaid-link-sdk: 9eb0f71dad94b3bdde649c7a384cba93024af46c
react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4
react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c
react-native-safe-area-context: 99b24a0c5acd0d5dcac2b1a7f18c49ea317be99a
react-native-view-shot: 705f999ac2a24e4e6c909c0ca65c732ed33ca2ff
react-native-webview: e771bc375f789ebfa02a26939a57dbc6fa897336
- React-NativeModulesApple: c57f3efe0df288a6532b726ad2d0322a9bf38472
- React-perflogger: 6bd153e776e6beed54c56b0847e1220a3ff92ba5
- React-RCTActionSheet: c0b62af44e610e69d9a2049a682f5dba4e9dff17
- React-RCTAnimation: f9bf9719258926aea9ecb8a2aa2595d3ff9a6022
- React-RCTAppDelegate: e5ac35d4dbd1fae7df3a62b47db04b6a8d151592
- React-RCTBlob: c4f1e69a6ef739aa42586b876d637dab4e3b5bed
- React-RCTImage: e5798f01aba248416c02a506cf5e6dfcba827638
- React-RCTLinking: f5b6227c879e33206f34e68924c458f57bbb96d9
- React-RCTNetwork: d5554fbfac1c618da3c8fa29933108ea22837788
- React-RCTSettings: 189c71e3e6146ba59f4f7e2cbeb494cf2ad42afa
- React-RCTText: 19425aea9d8b6ccae55a27916355b17ab577e56e
- React-RCTVibration: 388ac0e1455420895d1ca2548401eed964b038a6
- React-rncore: 755a331dd67b74662108f2d66a384454bf8dc1a1
- React-runtimeexecutor: 369ae9bb3f83b65201c0c8f7d50b72280b5a1dbc
- React-runtimescheduler: 837c1bebd2f84572db17698cd702ceaf585b0d9a
- React-utils: bcb57da67eec2711f8b353f6e3d33bd8e4b2efa3
- ReactCommon: 3ccb8fb14e6b3277e38c73b0ff5e4a1b8db017a9
+ React-NativeModulesApple: edb5ace14f73f4969df6e7b1f3e41bef0012740f
+ React-perflogger: 496a1a3dc6737f964107cb3ddae7f9e265ddda58
+ React-RCTActionSheet: 02904b932b50e680f4e26e7a686b33ebf7ef3c00
+ React-RCTAnimation: 88feaf0a85648fb8fd497ce749829774910276d6
+ React-RCTAppDelegate: 5792ac0f0feccb584765fdd7aa81ea320c4d9b0b
+ React-RCTBlob: 0dbc9e2a13d241b37d46b53e54630cbad1f0e141
+ React-RCTImage: b111645ab901f8e59fc68fbe31f5731bdbeef087
+ React-RCTLinking: 3d719727b4c098aad3588aa3559361ee0579f5de
+ React-RCTNetwork: b44d3580be05d74556ba4efbf53570f17e38f734
+ React-RCTSettings: c0c54b330442c29874cd4dae6e94190dc11a6f6f
+ React-RCTText: 9b9f5589d9b649d7246c3f336e116496df28cfe6
+ React-RCTVibration: 691c67f3beaf1d084ceed5eb5c1dddd9afa8591e
+ React-rncore: 142268f6c92e296dc079aadda3fade778562f9e4
+ React-runtimeexecutor: d465ba0c47ef3ed8281143f59605cacc2244d5c7
+ React-runtimescheduler: 4941cc1b3cf08b792fbf666342c9fc95f1969035
+ React-utils: b79f2411931f9d3ea5781404dcbb2fa8a837e13a
+ ReactCommon: 4b2bdcb50a3543e1c2b2849ad44533686610826d
RNAppleAuthentication: 0571c08da8c327ae2afc0261b48b4a515b0286a6
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
RNCClipboard: 41d8d918092ae8e676f18adada19104fa3e68495
@@ -1300,13 +1300,13 @@ SPEC CHECKSUMS:
RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c
RNReanimated: 020859659f64be2d30849a1fe88c821a7c3e0cbf
RNScreens: d037903436160a4b039d32606668350d2a808806
- RNSVG: 53c661b76829783cdaf9b7a57258f3d3b4c28315
+ RNSVG: ed492aaf3af9ca01bc945f7a149d76d62e73ec82
SDWebImage: a7f831e1a65eb5e285e3fb046a23fcfbf08e696d
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Turf: 469ce2c3d22e5e8e4818d5a3b254699a5c89efa4
VisionCamera: d3ec8883417a6a4a0e3a6ba37d81d22db7611601
- Yoga: 8796b55dba14d7004f980b54bcc9833ee45b28ce
+ Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14
diff --git a/jest.config.js b/jest.config.js
index 1f540a679b9a..6cf44b6b3695 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -23,6 +23,6 @@ module.exports = {
},
testEnvironment: 'jsdom',
setupFiles: ['/jest/setup.js', './node_modules/@react-native-google-signin/google-signin/jest/build/setup.js'],
- setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect'],
+ setupFilesAfterEnv: ['@testing-library/jest-native/extend-expect', '/jest/setupAfterEnv.js'],
cacheDirectory: '/.jest-cache',
};
diff --git a/jest/setupAfterEnv.js b/jest/setupAfterEnv.js
new file mode 100644
index 000000000000..6f7836b64dbb
--- /dev/null
+++ b/jest/setupAfterEnv.js
@@ -0,0 +1 @@
+jest.useRealTimers();
diff --git a/package-lock.json b/package-lock.json
index 6a366d6c61a1..ff0500eb385b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.71-5",
+ "version": "1.3.72-9",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.71-5",
+ "version": "1.3.72-9",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -69,8 +69,9 @@
"react-collapse": "^5.1.0",
"react-content-loader": "^6.1.0",
"react-dom": "18.1.0",
+ "react-error-boundary": "^4.0.11",
"react-map-gl": "^7.1.3",
- "react-native": "0.72.3",
+ "react-native": "0.72.4",
"react-native-blob-util": "^0.17.3",
"react-native-collapsible": "^1.6.0",
"react-native-config": "^1.4.5",
@@ -80,7 +81,7 @@
"react-native-fast-image": "^8.6.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "2.12.0",
- "react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#ee87343c3e827ff7818abc71b6bb04fcc1f120e0",
+ "react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#cef3ac29d9501091453136e1219e24c4ec9f9d76",
"react-native-haptic-feedback": "^1.13.0",
"react-native-image-pan-zoom": "^2.1.12",
"react-native-image-picker": "^5.1.0",
@@ -89,7 +90,7 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "1.0.77",
+ "react-native-onyx": "1.0.84",
"react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.7.1",
"react-native-performance": "^5.1.0",
@@ -138,7 +139,7 @@
"@octokit/plugin-paginate-rest": "3.1.0",
"@octokit/plugin-throttling": "4.1.0",
"@react-native-community/eslint-config": "3.0.0",
- "@react-native/metro-config": "^0.72.9",
+ "@react-native/metro-config": "^0.72.11",
"@react-navigation/devtools": "^6.0.10",
"@storybook/addon-a11y": "^6.5.9",
"@storybook/addon-essentials": "^7.0.0",
@@ -203,7 +204,7 @@
"jest-circus": "29.4.1",
"jest-cli": "29.4.1",
"jest-environment-jsdom": "^29.4.1",
- "metro-react-native-babel-preset": "0.76.7",
+ "metro-react-native-babel-preset": "0.76.8",
"mock-fs": "^4.13.0",
"onchange": "^7.1.0",
"portfinder": "^1.0.28",
@@ -6725,19 +6726,19 @@
}
},
"node_modules/@react-native-community/cli": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.5.tgz",
- "integrity": "sha512-wMXgKEWe6uesw7vyXKKjx5EDRog0QdXHxdgRguG14AjQRao1+4gXEWq2yyExOTi/GDY6dfJBUGTCwGQxhnk/Lg==",
- "dependencies": {
- "@react-native-community/cli-clean": "11.3.5",
- "@react-native-community/cli-config": "11.3.5",
- "@react-native-community/cli-debugger-ui": "11.3.5",
- "@react-native-community/cli-doctor": "11.3.5",
- "@react-native-community/cli-hermes": "11.3.5",
- "@react-native-community/cli-plugin-metro": "11.3.5",
- "@react-native-community/cli-server-api": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
- "@react-native-community/cli-types": "11.3.5",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.6.tgz",
+ "integrity": "sha512-bdwOIYTBVQ9VK34dsf6t3u6vOUU5lfdhKaAxiAVArjsr7Je88Bgs4sAbsOYsNK3tkE8G77U6wLpekknXcanlww==",
+ "dependencies": {
+ "@react-native-community/cli-clean": "11.3.6",
+ "@react-native-community/cli-config": "11.3.6",
+ "@react-native-community/cli-debugger-ui": "11.3.6",
+ "@react-native-community/cli-doctor": "11.3.6",
+ "@react-native-community/cli-hermes": "11.3.6",
+ "@react-native-community/cli-plugin-metro": "11.3.6",
+ "@react-native-community/cli-server-api": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-types": "11.3.6",
"chalk": "^4.1.2",
"commander": "^9.4.1",
"execa": "^5.0.0",
@@ -6745,7 +6746,7 @@
"fs-extra": "^8.1.0",
"graceful-fs": "^4.1.3",
"prompts": "^2.4.0",
- "semver": "^6.3.0"
+ "semver": "^7.5.2"
},
"bin": {
"react-native": "build/bin.js"
@@ -6755,11 +6756,11 @@
}
},
"node_modules/@react-native-community/cli-clean": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.5.tgz",
- "integrity": "sha512-1+7BU962wKkIkHRp/uW3jYbQKKGtU7L+R3g59D8K6uLccuxJYUBJv18753ojMa6SD3SAq5Xh31bAre+YwVcOTA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.6.tgz",
+ "integrity": "sha512-jOOaeG5ebSXTHweq1NznVJVAFKtTFWL4lWgUXl845bCGX7t1lL8xQNWHKwT8Oh1pGR2CI3cKmRjY4hBg+pEI9g==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"prompts": "^2.4.0"
@@ -6830,11 +6831,11 @@
}
},
"node_modules/@react-native-community/cli-config": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.5.tgz",
- "integrity": "sha512-fMblIsHlUleKfGsgWyjFJYfx1SqrsnhS/QXfA8w7iT6GrNOOjBp5UWx8+xlMDFcmOb9e42g1ExFDKl3n8FWkxQ==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.6.tgz",
+ "integrity": "sha512-edy7fwllSFLan/6BG6/rznOBCLPrjmJAE10FzkEqNLHowi0bckiAPg1+1jlgQ2qqAxV5kuk+c9eajVfQvPLYDA==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"cosmiconfig": "^5.1.0",
"deepmerge": "^4.3.0",
@@ -6953,22 +6954,22 @@
}
},
"node_modules/@react-native-community/cli-debugger-ui": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.5.tgz",
- "integrity": "sha512-o5JVCKEpPUXMX4r3p1cYjiy3FgdOEkezZcQ6owWEae2dYvV19lLYyJwnocm9Y7aG9PvpgI3PIMVh3KZbhS21eA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.6.tgz",
+ "integrity": "sha512-jhMOSN/iOlid9jn/A2/uf7HbC3u7+lGktpeGSLnHNw21iahFBzcpuO71ekEdlmTZ4zC/WyxBXw9j2ka33T358w==",
"dependencies": {
"serve-static": "^1.13.1"
}
},
"node_modules/@react-native-community/cli-doctor": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.5.tgz",
- "integrity": "sha512-+4BuFHjoV4FFjX5y60l0s6nS0agidb1izTVwsFixeFKW73LUkOLu+Ae5HI94RAFEPE4ePEVNgYX3FynIau6K0g==",
- "dependencies": {
- "@react-native-community/cli-config": "11.3.5",
- "@react-native-community/cli-platform-android": "11.3.5",
- "@react-native-community/cli-platform-ios": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.6.tgz",
+ "integrity": "sha512-UT/Tt6omVPi1j6JEX+CObc85eVFghSZwy4GR9JFMsO7gNg2Tvcu1RGWlUkrbmWMAMHw127LUu6TGK66Ugu1NLA==",
+ "dependencies": {
+ "@react-native-community/cli-config": "11.3.6",
+ "@react-native-community/cli-platform-android": "11.3.6",
+ "@react-native-community/cli-platform-ios": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"command-exists": "^1.2.8",
"envinfo": "^7.7.2",
@@ -6978,7 +6979,7 @@
"node-stream-zip": "^1.9.1",
"ora": "^5.4.1",
"prompts": "^2.4.0",
- "semver": "^6.3.0",
+ "semver": "^7.5.2",
"strip-ansi": "^5.2.0",
"sudo-prompt": "^9.0.0",
"wcwidth": "^1.0.1",
@@ -7043,14 +7044,6 @@
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
},
- "node_modules/@react-native-community/cli-doctor/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
"node_modules/@react-native-community/cli-doctor/node_modules/strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -7074,12 +7067,12 @@
}
},
"node_modules/@react-native-community/cli-hermes": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.5.tgz",
- "integrity": "sha512-+3m34hiaJpFel8BlJE7kJOaPzWR/8U8APZG2LXojbAdBAg99EGmQcwXIgsSVJFvH8h/nezf4DHbsPKigIe33zA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.6.tgz",
+ "integrity": "sha512-O55YAYGZ3XynpUdePPVvNuUPGPY0IJdctLAOHme73OvS80gNwfntHDXfmY70TGHWIfkK2zBhA0B+2v8s5aTyTA==",
"dependencies": {
- "@react-native-community/cli-platform-android": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-platform-android": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"hermes-profile-transformer": "^0.0.6",
"ip": "^1.1.5"
@@ -7155,11 +7148,11 @@
}
},
"node_modules/@react-native-community/cli-platform-android": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.5.tgz",
- "integrity": "sha512-s4Lj7FKxJ/BofGi/ifjPfrA9MjFwIgYpHnHBSlqtbsvPoSYzmVCU2qlWM8fb3AmkXIwyYt4A6MEr3MmNT2UoBg==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.6.tgz",
+ "integrity": "sha512-ZARrpLv5tn3rmhZc//IuDM1LSAdYnjUmjrp58RynlvjLDI4ZEjBAGCQmgysRgXAsK7ekMrfkZgemUczfn9td2A==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"glob": "^7.1.3",
@@ -7231,11 +7224,11 @@
}
},
"node_modules/@react-native-community/cli-platform-ios": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.5.tgz",
- "integrity": "sha512-ytJC/YCFD7P+KuQHOT5Jzh1ho2XbJEjq71yHa1gJP2PG/Q/uB4h1x2XpxDqv5iXU6E250yjvKMmkReKTW4CTig==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.6.tgz",
+ "integrity": "sha512-tZ9VbXWiRW+F+fbZzpLMZlj93g3Q96HpuMsS6DRhrTiG+vMQ3o6oPWSEEmMGOvJSYU7+y68Dc9ms2liC7VD6cw==",
"dependencies": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"fast-xml-parser": "^4.0.12",
@@ -7308,12 +7301,12 @@
}
},
"node_modules/@react-native-community/cli-plugin-metro": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.5.tgz",
- "integrity": "sha512-r9AekfeLKdblB7LfWB71IrNy1XM03WrByQlUQajUOZAP2NmUUBLl9pMZscPjJeOSgLpHB9ixEFTIOhTabri/qg==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.6.tgz",
+ "integrity": "sha512-D97racrPX3069ibyabJNKw9aJpVcaZrkYiEzsEnx50uauQtPDoQ1ELb/5c6CtMhAEGKoZ0B5MS23BbsSZcLs2g==",
"dependencies": {
- "@react-native-community/cli-server-api": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-server-api": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"metro": "0.76.7",
@@ -7325,6 +7318,29 @@
"readline": "^1.3.0"
}
},
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/@jest/types": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
+ "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
+ "dependencies": {
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/istanbul-reports": "^3.0.0",
+ "@types/node": "*",
+ "@types/yargs": "^16.0.0",
+ "chalk": "^4.0.0"
+ },
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/@types/yargs": {
+ "version": "16.0.5",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz",
+ "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==",
+ "dependencies": {
+ "@types/yargs-parser": "*"
+ }
+ },
"node_modules/@react-native-community/cli-plugin-metro/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -7354,6 +7370,24 @@
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@react-native-community/cli-plugin-metro/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -7370,6 +7404,28 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dependencies": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
"node_modules/@react-native-community/cli-plugin-metro/node_modules/has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
@@ -7378,6 +7434,492 @@
"node": ">=8"
}
},
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "dependencies": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-regex-util": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
+ "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==",
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-util": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
+ "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
+ "dependencies": {
+ "@jest/types": "^27.5.1",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "graceful-fs": "^4.2.9",
+ "picomatch": "^2.2.3"
+ },
+ "engines": {
+ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-util/node_modules/ci-info": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
+ "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/sibiraj-s"
+ }
+ ],
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-worker": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+ "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "dependencies": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/jest-worker/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.7.tgz",
+ "integrity": "sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ==",
+ "dependencies": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.0",
+ "@babel/parser": "^7.20.0",
+ "@babel/template": "^7.0.0",
+ "@babel/traverse": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "accepts": "^1.3.7",
+ "async": "^3.2.2",
+ "chalk": "^4.0.0",
+ "ci-info": "^2.0.0",
+ "connect": "^3.6.5",
+ "debug": "^2.2.0",
+ "denodeify": "^1.2.1",
+ "error-stack-parser": "^2.0.6",
+ "graceful-fs": "^4.2.4",
+ "hermes-parser": "0.12.0",
+ "image-size": "^1.0.2",
+ "invariant": "^2.2.4",
+ "jest-worker": "^27.2.0",
+ "jsc-safe-url": "^0.2.2",
+ "lodash.throttle": "^4.1.1",
+ "metro-babel-transformer": "0.76.7",
+ "metro-cache": "0.76.7",
+ "metro-cache-key": "0.76.7",
+ "metro-config": "0.76.7",
+ "metro-core": "0.76.7",
+ "metro-file-map": "0.76.7",
+ "metro-inspector-proxy": "0.76.7",
+ "metro-minify-terser": "0.76.7",
+ "metro-minify-uglify": "0.76.7",
+ "metro-react-native-babel-preset": "0.76.7",
+ "metro-resolver": "0.76.7",
+ "metro-runtime": "0.76.7",
+ "metro-source-map": "0.76.7",
+ "metro-symbolicate": "0.76.7",
+ "metro-transform-plugins": "0.76.7",
+ "metro-transform-worker": "0.76.7",
+ "mime-types": "^2.1.27",
+ "node-fetch": "^2.2.0",
+ "nullthrows": "^1.1.1",
+ "rimraf": "^3.0.2",
+ "serialize-error": "^2.1.0",
+ "source-map": "^0.5.6",
+ "strip-ansi": "^6.0.0",
+ "throat": "^5.0.0",
+ "ws": "^7.5.1",
+ "yargs": "^17.6.2"
+ },
+ "bin": {
+ "metro": "src/cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-babel-transformer": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz",
+ "integrity": "sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw==",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "hermes-parser": "0.12.0",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-cache": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.7.tgz",
+ "integrity": "sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg==",
+ "dependencies": {
+ "metro-core": "0.76.7",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-cache-key": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.7.tgz",
+ "integrity": "sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ==",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-config": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.7.tgz",
+ "integrity": "sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg==",
+ "dependencies": {
+ "connect": "^3.6.5",
+ "cosmiconfig": "^5.0.5",
+ "jest-validate": "^29.2.1",
+ "metro": "0.76.7",
+ "metro-cache": "0.76.7",
+ "metro-core": "0.76.7",
+ "metro-runtime": "0.76.7"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-core": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.7.tgz",
+ "integrity": "sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw==",
+ "dependencies": {
+ "lodash.throttle": "^4.1.1",
+ "metro-resolver": "0.76.7"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-file-map": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.7.tgz",
+ "integrity": "sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw==",
+ "dependencies": {
+ "anymatch": "^3.0.3",
+ "debug": "^2.2.0",
+ "fb-watchman": "^2.0.0",
+ "graceful-fs": "^4.2.4",
+ "invariant": "^2.2.4",
+ "jest-regex-util": "^27.0.6",
+ "jest-util": "^27.2.0",
+ "jest-worker": "^27.2.0",
+ "micromatch": "^4.0.4",
+ "node-abort-controller": "^3.1.1",
+ "nullthrows": "^1.1.1",
+ "walker": "^1.0.7"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "optionalDependencies": {
+ "fsevents": "^2.3.2"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-inspector-proxy": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz",
+ "integrity": "sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg==",
+ "dependencies": {
+ "connect": "^3.6.5",
+ "debug": "^2.2.0",
+ "node-fetch": "^2.2.0",
+ "ws": "^7.5.1",
+ "yargs": "^17.6.2"
+ },
+ "bin": {
+ "metro-inspector-proxy": "src/cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-minify-terser": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz",
+ "integrity": "sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA==",
+ "dependencies": {
+ "terser": "^5.15.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-minify-uglify": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz",
+ "integrity": "sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw==",
+ "dependencies": {
+ "uglify-es": "^3.1.9"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-react-native-babel-preset": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz",
+ "integrity": "sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw==",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "@babel/plugin-proposal-async-generator-functions": "^7.0.0",
+ "@babel/plugin-proposal-class-properties": "^7.18.0",
+ "@babel/plugin-proposal-export-default-from": "^7.0.0",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
+ "@babel/plugin-proposal-numeric-separator": "^7.0.0",
+ "@babel/plugin-proposal-object-rest-spread": "^7.20.0",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
+ "@babel/plugin-proposal-optional-chaining": "^7.20.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+ "@babel/plugin-syntax-export-default-from": "^7.0.0",
+ "@babel/plugin-syntax-flow": "^7.18.0",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
+ "@babel/plugin-syntax-optional-chaining": "^7.0.0",
+ "@babel/plugin-transform-arrow-functions": "^7.0.0",
+ "@babel/plugin-transform-async-to-generator": "^7.20.0",
+ "@babel/plugin-transform-block-scoping": "^7.0.0",
+ "@babel/plugin-transform-classes": "^7.0.0",
+ "@babel/plugin-transform-computed-properties": "^7.0.0",
+ "@babel/plugin-transform-destructuring": "^7.20.0",
+ "@babel/plugin-transform-flow-strip-types": "^7.20.0",
+ "@babel/plugin-transform-function-name": "^7.0.0",
+ "@babel/plugin-transform-literals": "^7.0.0",
+ "@babel/plugin-transform-modules-commonjs": "^7.0.0",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
+ "@babel/plugin-transform-parameters": "^7.0.0",
+ "@babel/plugin-transform-react-display-name": "^7.0.0",
+ "@babel/plugin-transform-react-jsx": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-source": "^7.0.0",
+ "@babel/plugin-transform-runtime": "^7.0.0",
+ "@babel/plugin-transform-shorthand-properties": "^7.0.0",
+ "@babel/plugin-transform-spread": "^7.0.0",
+ "@babel/plugin-transform-sticky-regex": "^7.0.0",
+ "@babel/plugin-transform-typescript": "^7.5.0",
+ "@babel/plugin-transform-unicode-regex": "^7.0.0",
+ "@babel/template": "^7.0.0",
+ "babel-plugin-transform-flow-enums": "^0.0.2",
+ "react-refresh": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "@babel/core": "*"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-react-native-babel-transformer": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz",
+ "integrity": "sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA==",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "babel-preset-fbjs": "^3.4.0",
+ "hermes-parser": "0.12.0",
+ "metro-react-native-babel-preset": "0.76.7",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "@babel/core": "*"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-resolver": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.7.tgz",
+ "integrity": "sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA==",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-runtime": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.7.tgz",
+ "integrity": "sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug==",
+ "dependencies": {
+ "@babel/runtime": "^7.0.0",
+ "react-refresh": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-source-map": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.7.tgz",
+ "integrity": "sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w==",
+ "dependencies": {
+ "@babel/traverse": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "invariant": "^2.2.4",
+ "metro-symbolicate": "0.76.7",
+ "nullthrows": "^1.1.1",
+ "ob1": "0.76.7",
+ "source-map": "^0.5.6",
+ "vlq": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-symbolicate": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz",
+ "integrity": "sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ==",
+ "dependencies": {
+ "invariant": "^2.2.4",
+ "metro-source-map": "0.76.7",
+ "nullthrows": "^1.1.1",
+ "source-map": "^0.5.6",
+ "through2": "^2.0.1",
+ "vlq": "^1.0.0"
+ },
+ "bin": {
+ "metro-symbolicate": "src/index.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-transform-plugins": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz",
+ "integrity": "sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg==",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.0",
+ "@babel/template": "^7.0.0",
+ "@babel/traverse": "^7.20.0",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/metro-transform-worker": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz",
+ "integrity": "sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw==",
+ "dependencies": {
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.0",
+ "@babel/parser": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "babel-preset-fbjs": "^3.4.0",
+ "metro": "0.76.7",
+ "metro-babel-transformer": "0.76.7",
+ "metro-cache": "0.76.7",
+ "metro-cache-key": "0.76.7",
+ "metro-source-map": "0.76.7",
+ "metro-transform-plugins": "0.76.7",
+ "nullthrows": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/ob1": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.7.tgz",
+ "integrity": "sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ==",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dependencies": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/react-refresh": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
+ "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/serialize-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
+ "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/@react-native-community/cli-plugin-metro/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -7389,13 +7931,66 @@
"node": ">=8"
}
},
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "engines": {
+ "node": ">=8.3.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": "^5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@react-native-community/cli-plugin-metro/node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/@react-native-community/cli-server-api": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.5.tgz",
- "integrity": "sha512-PM/jF13uD1eAKuC84lntNuM5ZvJAtyb+H896P1dBIXa9boPLa3KejfUvNVoyOUJ5s8Ht25JKbc3yieV2+GMBDA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.6.tgz",
+ "integrity": "sha512-8GUKodPnURGtJ9JKg8yOHIRtWepPciI3ssXVw5jik7+dZ43yN8P5BqCoDaq8e1H1yRer27iiOfT7XVnwk8Dueg==",
"dependencies": {
- "@react-native-community/cli-debugger-ui": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-debugger-ui": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"compression": "^1.7.1",
"connect": "^3.6.5",
"errorhandler": "^1.5.1",
@@ -7483,9 +8078,9 @@
}
},
"node_modules/@react-native-community/cli-tools": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.5.tgz",
- "integrity": "sha512-zDklE1+ah/zL4BLxut5XbzqCj9KTHzbYBKX7//cXw2/0TpkNCaY9c+iKx//gZ5m7U1OKbb86Fm2b0AKtKVRf6Q==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.6.tgz",
+ "integrity": "sha512-JpmUTcDwAGiTzLsfMlIAYpCMSJ9w2Qlf7PU7mZIRyEu61UzEawyw83DkqfbzDPBuRwRnaeN44JX2CP/yTO3ThQ==",
"dependencies": {
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
@@ -7494,7 +8089,7 @@
"node-fetch": "^2.6.0",
"open": "^6.2.0",
"ora": "^5.4.1",
- "semver": "^6.3.0",
+ "semver": "^7.5.2",
"shell-quote": "^1.7.3"
}
},
@@ -7570,14 +8165,6 @@
"node": ">=8"
}
},
- "node_modules/@react-native-community/cli-tools/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
"node_modules/@react-native-community/cli-tools/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -7590,9 +8177,9 @@
}
},
"node_modules/@react-native-community/cli-types": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.5.tgz",
- "integrity": "sha512-pf0kdWMEfPSV/+8rcViDCFzbLMtWIHMZ8ay7hKwqaoWegsJ0oprSF2tSTH+LSC/7X1Beb9ssIvHj1m5C4es5Xg==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.6.tgz",
+ "integrity": "sha512-6DxjrMKx5x68N/tCJYVYRKAtlRHbtUVBZrnAvkxbRWFD9v4vhNgsPM0RQm8i2vRugeksnao5mbnRGpS6c0awCw==",
"dependencies": {
"joi": "^17.2.1"
}
@@ -7735,14 +8322,6 @@
"node": ">=8"
}
},
- "node_modules/@react-native-community/cli/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "bin": {
- "semver": "bin/semver.js"
- }
- },
"node_modules/@react-native-community/cli/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -7989,15 +8568,15 @@
"license": "MIT"
},
"node_modules/@react-native/metro-config": {
- "version": "0.72.9",
- "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.72.9.tgz",
- "integrity": "sha512-5MGmyDnXPeprRuvgPGE4LZ+e+ovofSd5YY6nFDwg6wbjRGOkeCRRlaTlQT+fjmv+zr4vYG+MUTKBlaO+fui/vA==",
+ "version": "0.72.11",
+ "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.72.11.tgz",
+ "integrity": "sha512-661EyQnDdVelyc0qP/ew7kKkGAh6N6KlkuPLC2SQ8sxaXskVU6fSuNlpLW4bUTBUDFKG8gEOU2hp6rzk4wQnGQ==",
"dev": true,
"dependencies": {
"@react-native/js-polyfills": "^0.72.1",
- "metro-config": "0.76.7",
- "metro-react-native-babel-transformer": "0.76.7",
- "metro-runtime": "0.76.7"
+ "metro-config": "0.76.8",
+ "metro-react-native-babel-transformer": "0.76.8",
+ "metro-runtime": "0.76.8"
}
},
"node_modules/@react-native/normalize-color": {
@@ -8010,9 +8589,9 @@
"integrity": "sha512-285lfdqSXaqKuBbbtP9qL2tDrfxdOFtIMvkKadtleRQkdOxx+uzGvFr82KHmc/sSiMtfXGp7JnFYWVh4sFl7Yw=="
},
"node_modules/@react-native/virtualized-lists": {
- "version": "0.72.6",
- "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.6.tgz",
- "integrity": "sha512-JhT6ydu35LvbSKdwnhWDuGHMOwM0WAh9oza/X8vXHA8ELHRyQ/4p8eKz/bTQcbQziJaaleUURToGhFuCtgiMoA==",
+ "version": "0.72.8",
+ "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz",
+ "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==",
"dependencies": {
"invariant": "^2.2.4",
"nullthrows": "^1.1.1"
@@ -21037,7 +21616,8 @@
},
"node_modules/babel-plugin-syntax-trailing-function-commas": {
"version": "7.0.0-beta.0",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz",
+ "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ=="
},
"node_modules/babel-plugin-transform-class-properties": {
"version": "6.24.1",
@@ -21103,7 +21683,8 @@
},
"node_modules/babel-preset-fbjs": {
"version": "3.4.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz",
+ "integrity": "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==",
"dependencies": {
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
@@ -22668,9 +23249,9 @@
}
},
"node_modules/cli-spinners": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz",
- "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==",
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz",
+ "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==",
"engines": {
"node": ">=6"
},
@@ -23137,7 +23718,8 @@
},
"node_modules/connect": {
"version": "3.7.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
"dependencies": {
"debug": "2.6.9",
"finalhandler": "1.1.2",
@@ -23158,14 +23740,16 @@
},
"node_modules/connect/node_modules/debug": {
"version": "2.6.9",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/connect/node_modules/finalhandler": {
"version": "1.1.2",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
@@ -23181,11 +23765,13 @@
},
"node_modules/connect/node_modules/ms": {
"version": "2.0.0",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"node_modules/connect/node_modules/on-finished": {
"version": "2.3.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
"dependencies": {
"ee-first": "1.1.1"
},
@@ -23195,7 +23781,8 @@
},
"node_modules/connect/node_modules/statuses": {
"version": "1.5.0",
- "license": "MIT",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
"engines": {
"node": ">= 0.6"
}
@@ -24571,7 +25158,8 @@
},
"node_modules/denodeify": {
"version": "1.2.1",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
+ "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg=="
},
"node_modules/depd": {
"version": "2.0.0",
@@ -33571,9 +34159,9 @@
}
},
"node_modules/joi": {
- "version": "17.9.2",
- "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz",
- "integrity": "sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==",
+ "version": "17.10.1",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.1.tgz",
+ "integrity": "sha512-vIiDxQKmRidUVp8KngT8MZSOcmRVm2zV7jbMjNYWuHcJWI0bUck3nRTGQjhpPlQenIQIBC5Vp9AhcnHbWQqafw==",
"dependencies": {
"@hapi/hoek": "^9.0.0",
"@hapi/topo": "^5.0.0",
@@ -34233,7 +34821,8 @@
},
"node_modules/lodash.throttle": {
"version": "4.1.1",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
},
"node_modules/lodash.truncate": {
"version": "4.4.2",
@@ -35620,9 +36209,10 @@
}
},
"node_modules/metro": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.7.tgz",
- "integrity": "sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.8.tgz",
+ "integrity": "sha512-oQA3gLzrrYv3qKtuWArMgHPbHu8odZOD9AoavrqSFllkPgOtmkBvNNDLCELqv5SjBfqjISNffypg+5UGG3y0pg==",
+ "dev": true,
"dependencies": {
"@babel/code-frame": "^7.0.0",
"@babel/core": "^7.20.0",
@@ -35646,22 +36236,22 @@
"jest-worker": "^27.2.0",
"jsc-safe-url": "^0.2.2",
"lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-config": "0.76.7",
- "metro-core": "0.76.7",
- "metro-file-map": "0.76.7",
- "metro-inspector-proxy": "0.76.7",
- "metro-minify-terser": "0.76.7",
- "metro-minify-uglify": "0.76.7",
- "metro-react-native-babel-preset": "0.76.7",
- "metro-resolver": "0.76.7",
- "metro-runtime": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-symbolicate": "0.76.7",
- "metro-transform-plugins": "0.76.7",
- "metro-transform-worker": "0.76.7",
+ "metro-babel-transformer": "0.76.8",
+ "metro-cache": "0.76.8",
+ "metro-cache-key": "0.76.8",
+ "metro-config": "0.76.8",
+ "metro-core": "0.76.8",
+ "metro-file-map": "0.76.8",
+ "metro-inspector-proxy": "0.76.8",
+ "metro-minify-terser": "0.76.8",
+ "metro-minify-uglify": "0.76.8",
+ "metro-react-native-babel-preset": "0.76.8",
+ "metro-resolver": "0.76.8",
+ "metro-runtime": "0.76.8",
+ "metro-source-map": "0.76.8",
+ "metro-symbolicate": "0.76.8",
+ "metro-transform-plugins": "0.76.8",
+ "metro-transform-worker": "0.76.8",
"mime-types": "^2.1.27",
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
@@ -35681,9 +36271,10 @@
}
},
"node_modules/metro-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.8.tgz",
+ "integrity": "sha512-Hh6PW34Ug/nShlBGxkwQJSgPGAzSJ9FwQXhUImkzdsDgVu6zj5bx258J8cJVSandjNoQ8nbaHK6CaHlnbZKbyA==",
+ "dev": true,
"dependencies": {
"@babel/core": "^7.20.0",
"hermes-parser": "0.12.0",
@@ -35694,11 +36285,12 @@
}
},
"node_modules/metro-cache": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.7.tgz",
- "integrity": "sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.8.tgz",
+ "integrity": "sha512-QBJSJIVNH7Hc/Yo6br/U/qQDUpiUdRgZ2ZBJmvAbmAKp2XDzsapnMwK/3BGj8JNWJF7OLrqrYHsRsukSbUBpvQ==",
+ "dev": true,
"dependencies": {
- "metro-core": "0.76.7",
+ "metro-core": "0.76.8",
"rimraf": "^3.0.2"
},
"engines": {
@@ -35706,25 +36298,27 @@
}
},
"node_modules/metro-cache-key": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.7.tgz",
- "integrity": "sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.8.tgz",
+ "integrity": "sha512-buKQ5xentPig9G6T37Ww/R/bC+/V1MA5xU/D8zjnhlelsrPG6w6LtHUS61ID3zZcMZqYaELWk5UIadIdDsaaLw==",
+ "dev": true,
"engines": {
"node": ">=16"
}
},
"node_modules/metro-config": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.7.tgz",
- "integrity": "sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.8.tgz",
+ "integrity": "sha512-SL1lfKB0qGHALcAk2zBqVgQZpazDYvYFGwCK1ikz0S6Y/CM2i2/HwuZN31kpX6z3mqjv/6KvlzaKoTb1otuSAA==",
+ "dev": true,
"dependencies": {
"connect": "^3.6.5",
"cosmiconfig": "^5.0.5",
"jest-validate": "^29.2.1",
- "metro": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-core": "0.76.7",
- "metro-runtime": "0.76.7"
+ "metro": "0.76.8",
+ "metro-cache": "0.76.8",
+ "metro-core": "0.76.8",
+ "metro-runtime": "0.76.8"
},
"engines": {
"node": ">=16"
@@ -35734,6 +36328,7 @@
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
"integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
"dependencies": {
"import-fresh": "^2.0.0",
"is-directory": "^0.3.1",
@@ -35748,6 +36343,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
"integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "dev": true,
"dependencies": {
"caller-path": "^2.0.0",
"resolve-from": "^3.0.0"
@@ -35760,6 +36356,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dev": true,
"dependencies": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
@@ -35772,26 +36369,29 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
"integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
+ "dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/metro-core": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.7.tgz",
- "integrity": "sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.8.tgz",
+ "integrity": "sha512-sl2QLFI3d1b1XUUGxwzw/KbaXXU/bvFYrSKz6Sg19AdYGWFyzsgZ1VISRIDf+HWm4R/TJXluhWMEkEtZuqi3qA==",
+ "dev": true,
"dependencies": {
"lodash.throttle": "^4.1.1",
- "metro-resolver": "0.76.7"
+ "metro-resolver": "0.76.8"
},
"engines": {
"node": ">=16"
}
},
"node_modules/metro-file-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.7.tgz",
- "integrity": "sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.8.tgz",
+ "integrity": "sha512-A/xP1YNEVwO1SUV9/YYo6/Y1MmzhL4ZnVgcJC3VmHp/BYVOXVStzgVbWv2wILe56IIMkfXU+jpXrGKKYhFyHVw==",
+ "dev": true,
"dependencies": {
"anymatch": "^3.0.3",
"debug": "^2.2.0",
@@ -35817,6 +36417,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
"integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
+ "dev": true,
"dependencies": {
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
@@ -35832,6 +36433,7 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz",
"integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==",
+ "dev": true,
"dependencies": {
"@types/yargs-parser": "*"
}
@@ -35840,6 +36442,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -35854,6 +36457,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -35869,6 +36473,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -35879,12 +36484,14 @@
"node_modules/metro-file-map/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"node_modules/metro-file-map/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -35893,6 +36500,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
"engines": {
"node": ">=8"
}
@@ -35901,6 +36509,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
"integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==",
+ "dev": true,
"engines": {
"node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0"
}
@@ -35909,6 +36518,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
"integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
+ "dev": true,
"dependencies": {
"@jest/types": "^27.5.1",
"@types/node": "*",
@@ -35925,6 +36535,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "dev": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -35938,6 +36549,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -35951,12 +36563,14 @@
"node_modules/metro-file-map/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"node_modules/metro-file-map/node_modules/supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -35965,9 +36579,10 @@
}
},
"node_modules/metro-inspector-proxy": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz",
- "integrity": "sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.8.tgz",
+ "integrity": "sha512-Us5o5UEd4Smgn1+TfHX4LvVPoWVo9VsVMn4Ldbk0g5CQx3Gu0ygc/ei2AKPGTwsOZmKxJeACj7yMH2kgxQP/iw==",
+ "dev": true,
"dependencies": {
"connect": "^3.6.5",
"debug": "^2.2.0",
@@ -35986,6 +36601,7 @@
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@@ -35999,6 +36615,7 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -36006,12 +36623,14 @@
"node_modules/metro-inspector-proxy/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"node_modules/metro-inspector-proxy/node_modules/ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "dev": true,
"engines": {
"node": ">=8.3.0"
},
@@ -36032,6 +36651,7 @@
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
"engines": {
"node": ">=10"
}
@@ -36040,6 +36660,7 @@
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@@ -36057,14 +36678,16 @@
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
"engines": {
"node": ">=12"
}
},
"node_modules/metro-minify-terser": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz",
- "integrity": "sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.8.tgz",
+ "integrity": "sha512-Orbvg18qXHCrSj1KbaeSDVYRy/gkro2PC7Fy2tDSH1c9RB4aH8tuMOIXnKJE+1SXxBtjWmQ5Yirwkth2DyyEZA==",
+ "dev": true,
"dependencies": {
"terser": "^5.15.0"
},
@@ -36073,9 +36696,10 @@
}
},
"node_modules/metro-minify-uglify": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz",
- "integrity": "sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.8.tgz",
+ "integrity": "sha512-6l8/bEvtVaTSuhG1FqS0+Mc8lZ3Bl4RI8SeRIifVLC21eeSDp4CEBUWSGjpFyUDfi6R5dXzYaFnSgMNyfxADiQ==",
+ "dev": true,
"dependencies": {
"uglify-es": "^3.1.9"
},
@@ -36084,9 +36708,10 @@
}
},
"node_modules/metro-react-native-babel-preset": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz",
- "integrity": "sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.8.tgz",
+ "integrity": "sha512-Ptza08GgqzxEdK8apYsjTx2S8WDUlS2ilBlu9DR1CUcHmg4g3kOkFylZroogVAUKtpYQNYwAvdsjmrSdDNtiAg==",
+ "dev": true,
"dependencies": {
"@babel/core": "^7.20.0",
"@babel/plugin-proposal-async-generator-functions": "^7.0.0",
@@ -36137,20 +36762,22 @@
},
"node_modules/metro-react-native-babel-preset/node_modules/react-refresh": {
"version": "0.4.3",
+ "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/metro-react-native-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.8.tgz",
+ "integrity": "sha512-3h+LfS1WG1PAzhq8QF0kfXjxuXetbY/lgz8vYMQhgrMMp17WM1DNJD0gjx8tOGYbpbBC1qesJ45KMS4o5TA73A==",
+ "dev": true,
"dependencies": {
"@babel/core": "^7.20.0",
"babel-preset-fbjs": "^3.4.0",
"hermes-parser": "0.12.0",
- "metro-react-native-babel-preset": "0.76.7",
+ "metro-react-native-babel-preset": "0.76.8",
"nullthrows": "^1.1.1"
},
"engines": {
@@ -36161,17 +36788,18 @@
}
},
"node_modules/metro-resolver": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.7.tgz",
- "integrity": "sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.8.tgz",
+ "integrity": "sha512-KccOqc10vrzS7ZhG2NSnL2dh3uVydarB7nOhjreQ7C4zyWuiW9XpLC4h47KtGQv3Rnv/NDLJYeDqaJ4/+140HQ==",
+ "dev": true,
"engines": {
"node": ">=16"
}
},
"node_modules/metro-runtime": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.7.tgz",
- "integrity": "sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.8.tgz",
+ "integrity": "sha512-XKahvB+iuYJSCr3QqCpROli4B4zASAYpkK+j3a0CJmokxCDNbgyI4Fp88uIL6rNaZfN0Mv35S0b99SdFXIfHjg==",
"dependencies": {
"@babel/runtime": "^7.0.0",
"react-refresh": "^0.4.0"
@@ -36189,16 +36817,16 @@
}
},
"node_modules/metro-source-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.7.tgz",
- "integrity": "sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.8.tgz",
+ "integrity": "sha512-Hh0ncPsHPVf6wXQSqJqB3K9Zbudht4aUtNpNXYXSxH+pteWqGAXnjtPsRAnCsCWl38wL0jYF0rJDdMajUI3BDw==",
"dependencies": {
"@babel/traverse": "^7.20.0",
"@babel/types": "^7.20.0",
"invariant": "^2.2.4",
- "metro-symbolicate": "0.76.7",
+ "metro-symbolicate": "0.76.8",
"nullthrows": "^1.1.1",
- "ob1": "0.76.7",
+ "ob1": "0.76.8",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
},
@@ -36215,12 +36843,12 @@
}
},
"node_modules/metro-symbolicate": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz",
- "integrity": "sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.8.tgz",
+ "integrity": "sha512-LrRL3uy2VkzrIXVlxoPtqb40J6Bf1mlPNmUQewipc3qfKKFgtPHBackqDy1YL0njDsWopCKcfGtFYLn0PTUn3w==",
"dependencies": {
"invariant": "^2.2.4",
- "metro-source-map": "0.76.7",
+ "metro-source-map": "0.76.8",
"nullthrows": "^1.1.1",
"source-map": "^0.5.6",
"through2": "^2.0.1",
@@ -36242,9 +36870,10 @@
}
},
"node_modules/metro-transform-plugins": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz",
- "integrity": "sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.8.tgz",
+ "integrity": "sha512-PlkGTQNqS51Bx4vuufSQCdSn2R2rt7korzngo+b5GCkeX5pjinPjnO2kNhQ8l+5bO0iUD/WZ9nsM2PGGKIkWFA==",
+ "dev": true,
"dependencies": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
@@ -36257,21 +36886,22 @@
}
},
"node_modules/metro-transform-worker": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz",
- "integrity": "sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.8.tgz",
+ "integrity": "sha512-mE1fxVAnJKmwwJyDtThildxxos9+DGs9+vTrx2ktSFMEVTtXS/bIv2W6hux1pqivqAfyJpTeACXHk5u2DgGvIQ==",
+ "dev": true,
"dependencies": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
"@babel/parser": "^7.20.0",
"@babel/types": "^7.20.0",
"babel-preset-fbjs": "^3.4.0",
- "metro": "0.76.7",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-transform-plugins": "0.76.7",
+ "metro": "0.76.8",
+ "metro-babel-transformer": "0.76.8",
+ "metro-cache": "0.76.8",
+ "metro-cache-key": "0.76.8",
+ "metro-source-map": "0.76.8",
+ "metro-transform-plugins": "0.76.8",
"nullthrows": "^1.1.1"
},
"engines": {
@@ -36282,6 +36912,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -36296,6 +36927,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -36310,12 +36942,14 @@
"node_modules/metro/node_modules/ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
},
"node_modules/metro/node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@@ -36329,6 +36963,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -36339,12 +36974,14 @@
"node_modules/metro/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"node_modules/metro/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
"dependencies": {
"ms": "2.0.0"
}
@@ -36353,6 +36990,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
"engines": {
"node": ">=8"
}
@@ -36361,6 +36999,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "dev": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -36374,6 +37013,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -36387,12 +37027,14 @@
"node_modules/metro/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"node_modules/metro/node_modules/serialize-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
"integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==",
+ "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -36401,6 +37043,7 @@
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
"integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -36409,6 +37052,7 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -36420,6 +37064,7 @@
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "dev": true,
"engines": {
"node": ">=8.3.0"
},
@@ -36440,6 +37085,7 @@
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
"engines": {
"node": ">=10"
}
@@ -36448,6 +37094,7 @@
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@@ -36465,6 +37112,7 @@
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
"engines": {
"node": ">=12"
}
@@ -38007,9 +38655,9 @@
"license": "MIT"
},
"node_modules/ob1": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.7.tgz",
- "integrity": "sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.8.tgz",
+ "integrity": "sha512-dlBkJJV5M/msj9KYA9upc+nUWVwuOFFTbu28X6kZeGwcuW+JxaHSBZ70SYQnk5M+j5JbNLR6yKHmgW4M5E7X5g==",
"engines": {
"node": ">=16"
}
@@ -40187,6 +40835,17 @@
"react": "^18.1.0"
}
},
+ "node_modules/react-error-boundary": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.11.tgz",
+ "integrity": "sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==",
+ "dependencies": {
+ "@babel/runtime": "^7.12.5"
+ },
+ "peerDependencies": {
+ "react": ">=16.13.1"
+ }
+ },
"node_modules/react-freeze": {
"version": "1.0.3",
"license": "MIT",
@@ -40234,20 +40893,20 @@
}
},
"node_modules/react-native": {
- "version": "0.72.3",
- "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.3.tgz",
- "integrity": "sha512-QqISi+JVmCssNP2FlQ4MWhlc4O/I00MRE1/GClvyZ8h/6kdsyk/sOirkYdZqX3+DrJfI3q+OnyMnsyaXIQ/5tQ==",
+ "version": "0.72.4",
+ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.4.tgz",
+ "integrity": "sha512-+vrObi0wZR+NeqL09KihAAdVlQ9IdplwznJWtYrjnQ4UbCW6rkzZJebRsugwUneSOKNFaHFEo1uKU89HsgtYBg==",
"dependencies": {
"@jest/create-cache-key-function": "^29.2.1",
- "@react-native-community/cli": "11.3.5",
- "@react-native-community/cli-platform-android": "11.3.5",
- "@react-native-community/cli-platform-ios": "11.3.5",
+ "@react-native-community/cli": "11.3.6",
+ "@react-native-community/cli-platform-android": "11.3.6",
+ "@react-native-community/cli-platform-ios": "11.3.6",
"@react-native/assets-registry": "^0.72.0",
"@react-native/codegen": "^0.72.6",
"@react-native/gradle-plugin": "^0.72.11",
"@react-native/js-polyfills": "^0.72.1",
"@react-native/normalize-colors": "^0.72.0",
- "@react-native/virtualized-lists": "^0.72.6",
+ "@react-native/virtualized-lists": "^0.72.8",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"base64-js": "^1.1.2",
@@ -40258,8 +40917,8 @@
"jest-environment-node": "^29.2.1",
"jsc-android": "^250231.0.0",
"memoize-one": "^5.0.0",
- "metro-runtime": "0.76.7",
- "metro-source-map": "0.76.7",
+ "metro-runtime": "0.76.8",
+ "metro-source-map": "0.76.8",
"mkdirp": "^0.5.1",
"nullthrows": "^1.1.1",
"pretty-format": "^26.5.2",
@@ -40439,8 +41098,8 @@
},
"node_modules/react-native-google-places-autocomplete": {
"version": "2.5.1",
- "resolved": "git+ssh://git@github.com/Expensify/react-native-google-places-autocomplete.git#ee87343c3e827ff7818abc71b6bb04fcc1f120e0",
- "integrity": "sha512-OJWCz4Epj1p8tyNImWNykAqpd/X1MkNCFPY0dSbgiTJGbW4J5T4bC0PIUQ+ExjxWpWjcFaielTLdoSz0HfeIpw==",
+ "resolved": "git+ssh://git@github.com/Expensify/react-native-google-places-autocomplete.git#cef3ac29d9501091453136e1219e24c4ec9f9d76",
+ "integrity": "sha512-2z3ED8jOXasPTzBqvPwpG10LQsBArTRsYszmoz+TfqbgZrSBmP3c8rhaC//lx6Pvfs2r+KYWqJUrLf4mbCrjZw==",
"license": "MIT",
"dependencies": {
"lodash.debounce": "^4.0.8",
@@ -40544,9 +41203,9 @@
}
},
"node_modules/react-native-onyx": {
- "version": "1.0.77",
- "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.77.tgz",
- "integrity": "sha512-HmeS1Pz/BkKNbYuhWULC9I0VRBDt8yadG0ZFIW6wuZ+VajhjD960qh7Il1+XzEBI6Vb4d7BZkPcad87ad1IEOQ==",
+ "version": "1.0.84",
+ "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.84.tgz",
+ "integrity": "sha512-qQ+o+qS5ucZLbKbG5kI0UsC42N4h1Pprg/1D7PqjDeVanS3iUv33rT4fbrHuar77g0DSTA1/M8bC2WmYrShS9A==",
"dependencies": {
"ascii-table": "0.0.9",
"fast-equals": "^4.0.3",
@@ -40559,6 +41218,7 @@
"peerDependencies": {
"idb-keyval": "^6.2.1",
"react": ">=18.1.0",
+ "react-dom": ">=18.1.0",
"react-native-device-info": "^10.3.0",
"react-native-performance": "^5.1.0",
"react-native-quick-sqlite": "^8.0.0-beta.2"
@@ -44997,7 +45657,8 @@
},
"node_modules/throat": {
"version": "5.0.0",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
+ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="
},
"node_modules/throttle-debounce": {
"version": "3.0.1",
@@ -46368,7 +47029,8 @@
},
"node_modules/vlq": {
"version": "1.0.1",
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz",
+ "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="
},
"node_modules/vm-browserify": {
"version": "1.1.2",
@@ -52492,19 +53154,19 @@
"requires": {}
},
"@react-native-community/cli": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.5.tgz",
- "integrity": "sha512-wMXgKEWe6uesw7vyXKKjx5EDRog0QdXHxdgRguG14AjQRao1+4gXEWq2yyExOTi/GDY6dfJBUGTCwGQxhnk/Lg==",
- "requires": {
- "@react-native-community/cli-clean": "11.3.5",
- "@react-native-community/cli-config": "11.3.5",
- "@react-native-community/cli-debugger-ui": "11.3.5",
- "@react-native-community/cli-doctor": "11.3.5",
- "@react-native-community/cli-hermes": "11.3.5",
- "@react-native-community/cli-plugin-metro": "11.3.5",
- "@react-native-community/cli-server-api": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
- "@react-native-community/cli-types": "11.3.5",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli/-/cli-11.3.6.tgz",
+ "integrity": "sha512-bdwOIYTBVQ9VK34dsf6t3u6vOUU5lfdhKaAxiAVArjsr7Je88Bgs4sAbsOYsNK3tkE8G77U6wLpekknXcanlww==",
+ "requires": {
+ "@react-native-community/cli-clean": "11.3.6",
+ "@react-native-community/cli-config": "11.3.6",
+ "@react-native-community/cli-debugger-ui": "11.3.6",
+ "@react-native-community/cli-doctor": "11.3.6",
+ "@react-native-community/cli-hermes": "11.3.6",
+ "@react-native-community/cli-plugin-metro": "11.3.6",
+ "@react-native-community/cli-server-api": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
+ "@react-native-community/cli-types": "11.3.6",
"chalk": "^4.1.2",
"commander": "^9.4.1",
"execa": "^5.0.0",
@@ -52512,7 +53174,7 @@
"fs-extra": "^8.1.0",
"graceful-fs": "^4.1.3",
"prompts": "^2.4.0",
- "semver": "^6.3.0"
+ "semver": "^7.5.2"
},
"dependencies": {
"ansi-styles": {
@@ -52611,11 +53273,6 @@
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
},
- "semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
- },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -52632,11 +53289,11 @@
}
},
"@react-native-community/cli-clean": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.5.tgz",
- "integrity": "sha512-1+7BU962wKkIkHRp/uW3jYbQKKGtU7L+R3g59D8K6uLccuxJYUBJv18753ojMa6SD3SAq5Xh31bAre+YwVcOTA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-clean/-/cli-clean-11.3.6.tgz",
+ "integrity": "sha512-jOOaeG5ebSXTHweq1NznVJVAFKtTFWL4lWgUXl845bCGX7t1lL8xQNWHKwT8Oh1pGR2CI3cKmRjY4hBg+pEI9g==",
"requires": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"prompts": "^2.4.0"
@@ -52688,11 +53345,11 @@
}
},
"@react-native-community/cli-config": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.5.tgz",
- "integrity": "sha512-fMblIsHlUleKfGsgWyjFJYfx1SqrsnhS/QXfA8w7iT6GrNOOjBp5UWx8+xlMDFcmOb9e42g1ExFDKl3n8FWkxQ==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-config/-/cli-config-11.3.6.tgz",
+ "integrity": "sha512-edy7fwllSFLan/6BG6/rznOBCLPrjmJAE10FzkEqNLHowi0bckiAPg1+1jlgQ2qqAxV5kuk+c9eajVfQvPLYDA==",
"requires": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"cosmiconfig": "^5.1.0",
"deepmerge": "^4.3.0",
@@ -52780,22 +53437,22 @@
}
},
"@react-native-community/cli-debugger-ui": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.5.tgz",
- "integrity": "sha512-o5JVCKEpPUXMX4r3p1cYjiy3FgdOEkezZcQ6owWEae2dYvV19lLYyJwnocm9Y7aG9PvpgI3PIMVh3KZbhS21eA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-debugger-ui/-/cli-debugger-ui-11.3.6.tgz",
+ "integrity": "sha512-jhMOSN/iOlid9jn/A2/uf7HbC3u7+lGktpeGSLnHNw21iahFBzcpuO71ekEdlmTZ4zC/WyxBXw9j2ka33T358w==",
"requires": {
"serve-static": "^1.13.1"
}
},
"@react-native-community/cli-doctor": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.5.tgz",
- "integrity": "sha512-+4BuFHjoV4FFjX5y60l0s6nS0agidb1izTVwsFixeFKW73LUkOLu+Ae5HI94RAFEPE4ePEVNgYX3FynIau6K0g==",
- "requires": {
- "@react-native-community/cli-config": "11.3.5",
- "@react-native-community/cli-platform-android": "11.3.5",
- "@react-native-community/cli-platform-ios": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-doctor/-/cli-doctor-11.3.6.tgz",
+ "integrity": "sha512-UT/Tt6omVPi1j6JEX+CObc85eVFghSZwy4GR9JFMsO7gNg2Tvcu1RGWlUkrbmWMAMHw127LUu6TGK66Ugu1NLA==",
+ "requires": {
+ "@react-native-community/cli-config": "11.3.6",
+ "@react-native-community/cli-platform-android": "11.3.6",
+ "@react-native-community/cli-platform-ios": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"command-exists": "^1.2.8",
"envinfo": "^7.7.2",
@@ -52805,7 +53462,7 @@
"node-stream-zip": "^1.9.1",
"ora": "^5.4.1",
"prompts": "^2.4.0",
- "semver": "^6.3.0",
+ "semver": "^7.5.2",
"strip-ansi": "^5.2.0",
"sudo-prompt": "^9.0.0",
"wcwidth": "^1.0.1",
@@ -52852,11 +53509,6 @@
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
"integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg=="
},
- "semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
- },
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
@@ -52876,12 +53528,12 @@
}
},
"@react-native-community/cli-hermes": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.5.tgz",
- "integrity": "sha512-+3m34hiaJpFel8BlJE7kJOaPzWR/8U8APZG2LXojbAdBAg99EGmQcwXIgsSVJFvH8h/nezf4DHbsPKigIe33zA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-hermes/-/cli-hermes-11.3.6.tgz",
+ "integrity": "sha512-O55YAYGZ3XynpUdePPVvNuUPGPY0IJdctLAOHme73OvS80gNwfntHDXfmY70TGHWIfkK2zBhA0B+2v8s5aTyTA==",
"requires": {
- "@react-native-community/cli-platform-android": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-platform-android": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"hermes-profile-transformer": "^0.0.6",
"ip": "^1.1.5"
@@ -52938,11 +53590,11 @@
}
},
"@react-native-community/cli-platform-android": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.5.tgz",
- "integrity": "sha512-s4Lj7FKxJ/BofGi/ifjPfrA9MjFwIgYpHnHBSlqtbsvPoSYzmVCU2qlWM8fb3AmkXIwyYt4A6MEr3MmNT2UoBg==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-android/-/cli-platform-android-11.3.6.tgz",
+ "integrity": "sha512-ZARrpLv5tn3rmhZc//IuDM1LSAdYnjUmjrp58RynlvjLDI4ZEjBAGCQmgysRgXAsK7ekMrfkZgemUczfn9td2A==",
"requires": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"glob": "^7.1.3",
@@ -52995,11 +53647,11 @@
}
},
"@react-native-community/cli-platform-ios": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.5.tgz",
- "integrity": "sha512-ytJC/YCFD7P+KuQHOT5Jzh1ho2XbJEjq71yHa1gJP2PG/Q/uB4h1x2XpxDqv5iXU6E250yjvKMmkReKTW4CTig==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-platform-ios/-/cli-platform-ios-11.3.6.tgz",
+ "integrity": "sha512-tZ9VbXWiRW+F+fbZzpLMZlj93g3Q96HpuMsS6DRhrTiG+vMQ3o6oPWSEEmMGOvJSYU7+y68Dc9ms2liC7VD6cw==",
"requires": {
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"fast-xml-parser": "^4.0.12",
@@ -53053,12 +53705,12 @@
}
},
"@react-native-community/cli-plugin-metro": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.5.tgz",
- "integrity": "sha512-r9AekfeLKdblB7LfWB71IrNy1XM03WrByQlUQajUOZAP2NmUUBLl9pMZscPjJeOSgLpHB9ixEFTIOhTabri/qg==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-plugin-metro/-/cli-plugin-metro-11.3.6.tgz",
+ "integrity": "sha512-D97racrPX3069ibyabJNKw9aJpVcaZrkYiEzsEnx50uauQtPDoQ1ELb/5c6CtMhAEGKoZ0B5MS23BbsSZcLs2g==",
"requires": {
- "@react-native-community/cli-server-api": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-server-api": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"chalk": "^4.1.2",
"execa": "^5.0.0",
"metro": "0.76.7",
@@ -53070,6 +53722,26 @@
"readline": "^1.3.0"
},
"dependencies": {
+ "@jest/types": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
+ "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
+ "requires": {
+ "@types/istanbul-lib-coverage": "^2.0.0",
+ "@types/istanbul-reports": "^3.0.0",
+ "@types/node": "*",
+ "@types/yargs": "^16.0.0",
+ "chalk": "^4.0.0"
+ }
+ },
+ "@types/yargs": {
+ "version": "16.0.5",
+ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz",
+ "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==",
+ "requires": {
+ "@types/yargs-parser": "*"
+ }
+ },
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@@ -53087,6 +53759,21 @@
"supports-color": "^7.1.0"
}
},
+ "ci-info": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+ },
+ "cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "requires": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -53100,11 +53787,404 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "cosmiconfig": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
+ "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "requires": {
+ "import-fresh": "^2.0.0",
+ "is-directory": "^0.3.1",
+ "js-yaml": "^3.13.1",
+ "parse-json": "^4.0.0"
+ }
+ },
+ "debug": {
+ "version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "requires": {
+ "ms": "2.0.0"
+ }
+ },
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
},
+ "import-fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
+ "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "requires": {
+ "caller-path": "^2.0.0",
+ "resolve-from": "^3.0.0"
+ }
+ },
+ "jest-regex-util": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
+ "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg=="
+ },
+ "jest-util": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
+ "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
+ "requires": {
+ "@jest/types": "^27.5.1",
+ "@types/node": "*",
+ "chalk": "^4.0.0",
+ "ci-info": "^3.2.0",
+ "graceful-fs": "^4.2.9",
+ "picomatch": "^2.2.3"
+ },
+ "dependencies": {
+ "ci-info": {
+ "version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz",
+ "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw=="
+ }
+ }
+ },
+ "jest-worker": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+ "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "requires": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "dependencies": {
+ "supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "requires": {
+ "has-flag": "^4.0.0"
+ }
+ }
+ }
+ },
+ "metro": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.7.tgz",
+ "integrity": "sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ==",
+ "requires": {
+ "@babel/code-frame": "^7.0.0",
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.0",
+ "@babel/parser": "^7.20.0",
+ "@babel/template": "^7.0.0",
+ "@babel/traverse": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "accepts": "^1.3.7",
+ "async": "^3.2.2",
+ "chalk": "^4.0.0",
+ "ci-info": "^2.0.0",
+ "connect": "^3.6.5",
+ "debug": "^2.2.0",
+ "denodeify": "^1.2.1",
+ "error-stack-parser": "^2.0.6",
+ "graceful-fs": "^4.2.4",
+ "hermes-parser": "0.12.0",
+ "image-size": "^1.0.2",
+ "invariant": "^2.2.4",
+ "jest-worker": "^27.2.0",
+ "jsc-safe-url": "^0.2.2",
+ "lodash.throttle": "^4.1.1",
+ "metro-babel-transformer": "0.76.7",
+ "metro-cache": "0.76.7",
+ "metro-cache-key": "0.76.7",
+ "metro-config": "0.76.7",
+ "metro-core": "0.76.7",
+ "metro-file-map": "0.76.7",
+ "metro-inspector-proxy": "0.76.7",
+ "metro-minify-terser": "0.76.7",
+ "metro-minify-uglify": "0.76.7",
+ "metro-react-native-babel-preset": "0.76.7",
+ "metro-resolver": "0.76.7",
+ "metro-runtime": "0.76.7",
+ "metro-source-map": "0.76.7",
+ "metro-symbolicate": "0.76.7",
+ "metro-transform-plugins": "0.76.7",
+ "metro-transform-worker": "0.76.7",
+ "mime-types": "^2.1.27",
+ "node-fetch": "^2.2.0",
+ "nullthrows": "^1.1.1",
+ "rimraf": "^3.0.2",
+ "serialize-error": "^2.1.0",
+ "source-map": "^0.5.6",
+ "strip-ansi": "^6.0.0",
+ "throat": "^5.0.0",
+ "ws": "^7.5.1",
+ "yargs": "^17.6.2"
+ }
+ },
+ "metro-babel-transformer": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz",
+ "integrity": "sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw==",
+ "requires": {
+ "@babel/core": "^7.20.0",
+ "hermes-parser": "0.12.0",
+ "nullthrows": "^1.1.1"
+ }
+ },
+ "metro-cache": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.7.tgz",
+ "integrity": "sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg==",
+ "requires": {
+ "metro-core": "0.76.7",
+ "rimraf": "^3.0.2"
+ }
+ },
+ "metro-cache-key": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.7.tgz",
+ "integrity": "sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ=="
+ },
+ "metro-config": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.7.tgz",
+ "integrity": "sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg==",
+ "requires": {
+ "connect": "^3.6.5",
+ "cosmiconfig": "^5.0.5",
+ "jest-validate": "^29.2.1",
+ "metro": "0.76.7",
+ "metro-cache": "0.76.7",
+ "metro-core": "0.76.7",
+ "metro-runtime": "0.76.7"
+ }
+ },
+ "metro-core": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.7.tgz",
+ "integrity": "sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw==",
+ "requires": {
+ "lodash.throttle": "^4.1.1",
+ "metro-resolver": "0.76.7"
+ }
+ },
+ "metro-file-map": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.7.tgz",
+ "integrity": "sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw==",
+ "requires": {
+ "anymatch": "^3.0.3",
+ "debug": "^2.2.0",
+ "fb-watchman": "^2.0.0",
+ "fsevents": "^2.3.2",
+ "graceful-fs": "^4.2.4",
+ "invariant": "^2.2.4",
+ "jest-regex-util": "^27.0.6",
+ "jest-util": "^27.2.0",
+ "jest-worker": "^27.2.0",
+ "micromatch": "^4.0.4",
+ "node-abort-controller": "^3.1.1",
+ "nullthrows": "^1.1.1",
+ "walker": "^1.0.7"
+ }
+ },
+ "metro-inspector-proxy": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz",
+ "integrity": "sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg==",
+ "requires": {
+ "connect": "^3.6.5",
+ "debug": "^2.2.0",
+ "node-fetch": "^2.2.0",
+ "ws": "^7.5.1",
+ "yargs": "^17.6.2"
+ }
+ },
+ "metro-minify-terser": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz",
+ "integrity": "sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA==",
+ "requires": {
+ "terser": "^5.15.0"
+ }
+ },
+ "metro-minify-uglify": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz",
+ "integrity": "sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw==",
+ "requires": {
+ "uglify-es": "^3.1.9"
+ }
+ },
+ "metro-react-native-babel-preset": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz",
+ "integrity": "sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw==",
+ "requires": {
+ "@babel/core": "^7.20.0",
+ "@babel/plugin-proposal-async-generator-functions": "^7.0.0",
+ "@babel/plugin-proposal-class-properties": "^7.18.0",
+ "@babel/plugin-proposal-export-default-from": "^7.0.0",
+ "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.0",
+ "@babel/plugin-proposal-numeric-separator": "^7.0.0",
+ "@babel/plugin-proposal-object-rest-spread": "^7.20.0",
+ "@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
+ "@babel/plugin-proposal-optional-chaining": "^7.20.0",
+ "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+ "@babel/plugin-syntax-export-default-from": "^7.0.0",
+ "@babel/plugin-syntax-flow": "^7.18.0",
+ "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0",
+ "@babel/plugin-syntax-optional-chaining": "^7.0.0",
+ "@babel/plugin-transform-arrow-functions": "^7.0.0",
+ "@babel/plugin-transform-async-to-generator": "^7.20.0",
+ "@babel/plugin-transform-block-scoping": "^7.0.0",
+ "@babel/plugin-transform-classes": "^7.0.0",
+ "@babel/plugin-transform-computed-properties": "^7.0.0",
+ "@babel/plugin-transform-destructuring": "^7.20.0",
+ "@babel/plugin-transform-flow-strip-types": "^7.20.0",
+ "@babel/plugin-transform-function-name": "^7.0.0",
+ "@babel/plugin-transform-literals": "^7.0.0",
+ "@babel/plugin-transform-modules-commonjs": "^7.0.0",
+ "@babel/plugin-transform-named-capturing-groups-regex": "^7.0.0",
+ "@babel/plugin-transform-parameters": "^7.0.0",
+ "@babel/plugin-transform-react-display-name": "^7.0.0",
+ "@babel/plugin-transform-react-jsx": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-self": "^7.0.0",
+ "@babel/plugin-transform-react-jsx-source": "^7.0.0",
+ "@babel/plugin-transform-runtime": "^7.0.0",
+ "@babel/plugin-transform-shorthand-properties": "^7.0.0",
+ "@babel/plugin-transform-spread": "^7.0.0",
+ "@babel/plugin-transform-sticky-regex": "^7.0.0",
+ "@babel/plugin-transform-typescript": "^7.5.0",
+ "@babel/plugin-transform-unicode-regex": "^7.0.0",
+ "@babel/template": "^7.0.0",
+ "babel-plugin-transform-flow-enums": "^0.0.2",
+ "react-refresh": "^0.4.0"
+ }
+ },
+ "metro-react-native-babel-transformer": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz",
+ "integrity": "sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA==",
+ "requires": {
+ "@babel/core": "^7.20.0",
+ "babel-preset-fbjs": "^3.4.0",
+ "hermes-parser": "0.12.0",
+ "metro-react-native-babel-preset": "0.76.7",
+ "nullthrows": "^1.1.1"
+ }
+ },
+ "metro-resolver": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.7.tgz",
+ "integrity": "sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA=="
+ },
+ "metro-runtime": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.7.tgz",
+ "integrity": "sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug==",
+ "requires": {
+ "@babel/runtime": "^7.0.0",
+ "react-refresh": "^0.4.0"
+ }
+ },
+ "metro-source-map": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.7.tgz",
+ "integrity": "sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w==",
+ "requires": {
+ "@babel/traverse": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "invariant": "^2.2.4",
+ "metro-symbolicate": "0.76.7",
+ "nullthrows": "^1.1.1",
+ "ob1": "0.76.7",
+ "source-map": "^0.5.6",
+ "vlq": "^1.0.0"
+ }
+ },
+ "metro-symbolicate": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz",
+ "integrity": "sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ==",
+ "requires": {
+ "invariant": "^2.2.4",
+ "metro-source-map": "0.76.7",
+ "nullthrows": "^1.1.1",
+ "source-map": "^0.5.6",
+ "through2": "^2.0.1",
+ "vlq": "^1.0.0"
+ }
+ },
+ "metro-transform-plugins": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz",
+ "integrity": "sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg==",
+ "requires": {
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.0",
+ "@babel/template": "^7.0.0",
+ "@babel/traverse": "^7.20.0",
+ "nullthrows": "^1.1.1"
+ }
+ },
+ "metro-transform-worker": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz",
+ "integrity": "sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw==",
+ "requires": {
+ "@babel/core": "^7.20.0",
+ "@babel/generator": "^7.20.0",
+ "@babel/parser": "^7.20.0",
+ "@babel/types": "^7.20.0",
+ "babel-preset-fbjs": "^3.4.0",
+ "metro": "0.76.7",
+ "metro-babel-transformer": "0.76.7",
+ "metro-cache": "0.76.7",
+ "metro-cache-key": "0.76.7",
+ "metro-source-map": "0.76.7",
+ "metro-transform-plugins": "0.76.7",
+ "nullthrows": "^1.1.1"
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ },
+ "ob1": {
+ "version": "0.76.7",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.7.tgz",
+ "integrity": "sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ=="
+ },
+ "parse-json": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
+ "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "requires": {
+ "error-ex": "^1.3.1",
+ "json-parse-better-errors": "^1.0.1"
+ }
+ },
+ "react-refresh": {
+ "version": "0.4.3",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz",
+ "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA=="
+ },
+ "resolve-from": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="
+ },
+ "serialize-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
+ "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
+ },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -53112,16 +54192,46 @@
"requires": {
"has-flag": "^4.0.0"
}
+ },
+ "ws": {
+ "version": "7.5.9",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+ "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "requires": {}
+ },
+ "y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+ },
+ "yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "requires": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ }
+ },
+ "yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
}
}
},
"@react-native-community/cli-server-api": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.5.tgz",
- "integrity": "sha512-PM/jF13uD1eAKuC84lntNuM5ZvJAtyb+H896P1dBIXa9boPLa3KejfUvNVoyOUJ5s8Ht25JKbc3yieV2+GMBDA==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-server-api/-/cli-server-api-11.3.6.tgz",
+ "integrity": "sha512-8GUKodPnURGtJ9JKg8yOHIRtWepPciI3ssXVw5jik7+dZ43yN8P5BqCoDaq8e1H1yRer27iiOfT7XVnwk8Dueg==",
"requires": {
- "@react-native-community/cli-debugger-ui": "11.3.5",
- "@react-native-community/cli-tools": "11.3.5",
+ "@react-native-community/cli-debugger-ui": "11.3.6",
+ "@react-native-community/cli-tools": "11.3.6",
"compression": "^1.7.1",
"connect": "^3.6.5",
"errorhandler": "^1.5.1",
@@ -53182,9 +54292,9 @@
}
},
"@react-native-community/cli-tools": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.5.tgz",
- "integrity": "sha512-zDklE1+ah/zL4BLxut5XbzqCj9KTHzbYBKX7//cXw2/0TpkNCaY9c+iKx//gZ5m7U1OKbb86Fm2b0AKtKVRf6Q==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-tools/-/cli-tools-11.3.6.tgz",
+ "integrity": "sha512-JpmUTcDwAGiTzLsfMlIAYpCMSJ9w2Qlf7PU7mZIRyEu61UzEawyw83DkqfbzDPBuRwRnaeN44JX2CP/yTO3ThQ==",
"requires": {
"appdirsjs": "^1.2.4",
"chalk": "^4.1.2",
@@ -53193,7 +54303,7 @@
"node-fetch": "^2.6.0",
"open": "^6.2.0",
"ora": "^5.4.1",
- "semver": "^6.3.0",
+ "semver": "^7.5.2",
"shell-quote": "^1.7.3"
},
"dependencies": {
@@ -53245,11 +54355,6 @@
"is-wsl": "^1.1.0"
}
},
- "semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="
- },
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -53261,9 +54366,9 @@
}
},
"@react-native-community/cli-types": {
- "version": "11.3.5",
- "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.5.tgz",
- "integrity": "sha512-pf0kdWMEfPSV/+8rcViDCFzbLMtWIHMZ8ay7hKwqaoWegsJ0oprSF2tSTH+LSC/7X1Beb9ssIvHj1m5C4es5Xg==",
+ "version": "11.3.6",
+ "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-11.3.6.tgz",
+ "integrity": "sha512-6DxjrMKx5x68N/tCJYVYRKAtlRHbtUVBZrnAvkxbRWFD9v4vhNgsPM0RQm8i2vRugeksnao5mbnRGpS6c0awCw==",
"requires": {
"joi": "^17.2.1"
}
@@ -53407,15 +54512,15 @@
"version": "0.72.1"
},
"@react-native/metro-config": {
- "version": "0.72.9",
- "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.72.9.tgz",
- "integrity": "sha512-5MGmyDnXPeprRuvgPGE4LZ+e+ovofSd5YY6nFDwg6wbjRGOkeCRRlaTlQT+fjmv+zr4vYG+MUTKBlaO+fui/vA==",
+ "version": "0.72.11",
+ "resolved": "https://registry.npmjs.org/@react-native/metro-config/-/metro-config-0.72.11.tgz",
+ "integrity": "sha512-661EyQnDdVelyc0qP/ew7kKkGAh6N6KlkuPLC2SQ8sxaXskVU6fSuNlpLW4bUTBUDFKG8gEOU2hp6rzk4wQnGQ==",
"dev": true,
"requires": {
"@react-native/js-polyfills": "^0.72.1",
- "metro-config": "0.76.7",
- "metro-react-native-babel-transformer": "0.76.7",
- "metro-runtime": "0.76.7"
+ "metro-config": "0.76.8",
+ "metro-react-native-babel-transformer": "0.76.8",
+ "metro-runtime": "0.76.8"
}
},
"@react-native/normalize-color": {
@@ -53427,9 +54532,9 @@
"integrity": "sha512-285lfdqSXaqKuBbbtP9qL2tDrfxdOFtIMvkKadtleRQkdOxx+uzGvFr82KHmc/sSiMtfXGp7JnFYWVh4sFl7Yw=="
},
"@react-native/virtualized-lists": {
- "version": "0.72.6",
- "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.6.tgz",
- "integrity": "sha512-JhT6ydu35LvbSKdwnhWDuGHMOwM0WAh9oza/X8vXHA8ELHRyQ/4p8eKz/bTQcbQziJaaleUURToGhFuCtgiMoA==",
+ "version": "0.72.8",
+ "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.72.8.tgz",
+ "integrity": "sha512-J3Q4Bkuo99k7mu+jPS9gSUSgq+lLRSI/+ahXNwV92XgJ/8UgOTxu2LPwhJnBk/sQKxq7E8WkZBnBiozukQMqrw==",
"requires": {
"invariant": "^2.2.4",
"nullthrows": "^1.1.1"
@@ -62639,7 +63744,9 @@
"dev": true
},
"babel-plugin-syntax-trailing-function-commas": {
- "version": "7.0.0-beta.0"
+ "version": "7.0.0-beta.0",
+ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz",
+ "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ=="
},
"babel-plugin-transform-class-properties": {
"version": "6.24.1",
@@ -62696,6 +63803,8 @@
},
"babel-preset-fbjs": {
"version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz",
+ "integrity": "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==",
"requires": {
"@babel/plugin-proposal-class-properties": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
@@ -63775,9 +64884,9 @@
}
},
"cli-spinners": {
- "version": "2.9.0",
- "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz",
- "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g=="
+ "version": "2.9.1",
+ "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz",
+ "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ=="
},
"cli-table3": {
"version": "0.6.3",
@@ -64096,6 +65205,8 @@
},
"connect": {
"version": "3.7.0",
+ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz",
+ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==",
"requires": {
"debug": "2.6.9",
"finalhandler": "1.1.2",
@@ -64105,12 +65216,16 @@
"dependencies": {
"debug": {
"version": "2.6.9",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"finalhandler": {
"version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
"requires": {
"debug": "2.6.9",
"encodeurl": "~1.0.2",
@@ -64122,16 +65237,22 @@
}
},
"ms": {
- "version": "2.0.0"
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
},
"on-finished": {
"version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==",
"requires": {
"ee-first": "1.1.1"
}
},
"statuses": {
- "version": "1.5.0"
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA=="
}
}
},
@@ -65063,7 +66184,9 @@
"dev": true
},
"denodeify": {
- "version": "1.2.1"
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz",
+ "integrity": "sha512-KNTihKNmQENUZeKu5fzfpzRqR5S2VMp4gl9RFHiWzj9DfvYQPMJ6XHKNaQxaGCXwPk6y9yme3aUoaiAe+KX+vg=="
},
"depd": {
"version": "2.0.0"
@@ -71163,9 +72286,9 @@
}
},
"joi": {
- "version": "17.9.2",
- "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.2.tgz",
- "integrity": "sha512-Itk/r+V4Dx0V3c7RLFdRh12IOjySm2/WGPMubBT92cQvRfYZhPM2W0hZlctjj72iES8jsRCwp7S/cRmWBnJ4nw==",
+ "version": "17.10.1",
+ "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.1.tgz",
+ "integrity": "sha512-vIiDxQKmRidUVp8KngT8MZSOcmRVm2zV7jbMjNYWuHcJWI0bUck3nRTGQjhpPlQenIQIBC5Vp9AhcnHbWQqafw==",
"requires": {
"@hapi/hoek": "^9.0.0",
"@hapi/topo": "^5.0.0",
@@ -71623,7 +72746,9 @@
"dev": true
},
"lodash.throttle": {
- "version": "4.1.1"
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
},
"lodash.truncate": {
"version": "4.4.2",
@@ -72627,9 +73752,10 @@
"dev": true
},
"metro": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.7.tgz",
- "integrity": "sha512-67ZGwDeumEPnrHI+pEDSKH2cx+C81Gx8Mn5qOtmGUPm/Up9Y4I1H2dJZ5n17MWzejNo0XAvPh0QL0CrlJEODVQ==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro/-/metro-0.76.8.tgz",
+ "integrity": "sha512-oQA3gLzrrYv3qKtuWArMgHPbHu8odZOD9AoavrqSFllkPgOtmkBvNNDLCELqv5SjBfqjISNffypg+5UGG3y0pg==",
+ "dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/core": "^7.20.0",
@@ -72653,22 +73779,22 @@
"jest-worker": "^27.2.0",
"jsc-safe-url": "^0.2.2",
"lodash.throttle": "^4.1.1",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-config": "0.76.7",
- "metro-core": "0.76.7",
- "metro-file-map": "0.76.7",
- "metro-inspector-proxy": "0.76.7",
- "metro-minify-terser": "0.76.7",
- "metro-minify-uglify": "0.76.7",
- "metro-react-native-babel-preset": "0.76.7",
- "metro-resolver": "0.76.7",
- "metro-runtime": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-symbolicate": "0.76.7",
- "metro-transform-plugins": "0.76.7",
- "metro-transform-worker": "0.76.7",
+ "metro-babel-transformer": "0.76.8",
+ "metro-cache": "0.76.8",
+ "metro-cache-key": "0.76.8",
+ "metro-config": "0.76.8",
+ "metro-core": "0.76.8",
+ "metro-file-map": "0.76.8",
+ "metro-inspector-proxy": "0.76.8",
+ "metro-minify-terser": "0.76.8",
+ "metro-minify-uglify": "0.76.8",
+ "metro-react-native-babel-preset": "0.76.8",
+ "metro-resolver": "0.76.8",
+ "metro-runtime": "0.76.8",
+ "metro-source-map": "0.76.8",
+ "metro-symbolicate": "0.76.8",
+ "metro-transform-plugins": "0.76.8",
+ "metro-transform-worker": "0.76.8",
"mime-types": "^2.1.27",
"node-fetch": "^2.2.0",
"nullthrows": "^1.1.1",
@@ -72685,6 +73811,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -72693,6 +73820,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -72701,12 +73829,14 @@
"ci-info": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz",
- "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ=="
+ "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==",
+ "dev": true
},
"cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@@ -72717,6 +73847,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
"requires": {
"color-name": "~1.1.4"
}
@@ -72724,12 +73855,14 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -72737,12 +73870,14 @@
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
},
"jest-worker": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "dev": true,
"requires": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -72753,6 +73888,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -72762,22 +73898,26 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"serialize-error": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz",
- "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw=="
+ "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==",
+ "dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -72786,17 +73926,20 @@
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "dev": true,
"requires": {}
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
},
"yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
"requires": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@@ -72810,14 +73953,16 @@
"yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true
}
}
},
"metro-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-bgr2OFn0J4r0qoZcHrwEvccF7g9k3wdgTOgk6gmGHrtlZ1Jn3oCpklW/DfZ9PzHfjY2mQammKTc19g/EFGyOJw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.76.8.tgz",
+ "integrity": "sha512-Hh6PW34Ug/nShlBGxkwQJSgPGAzSJ9FwQXhUImkzdsDgVu6zj5bx258J8cJVSandjNoQ8nbaHK6CaHlnbZKbyA==",
+ "dev": true,
"requires": {
"@babel/core": "^7.20.0",
"hermes-parser": "0.12.0",
@@ -72825,37 +73970,41 @@
}
},
"metro-cache": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.7.tgz",
- "integrity": "sha512-nWBMztrs5RuSxZRI7hgFgob5PhYDmxICh9FF8anm9/ito0u0vpPvRxt7sRu8fyeD2AHdXqE7kX32rWY0LiXgeg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.76.8.tgz",
+ "integrity": "sha512-QBJSJIVNH7Hc/Yo6br/U/qQDUpiUdRgZ2ZBJmvAbmAKp2XDzsapnMwK/3BGj8JNWJF7OLrqrYHsRsukSbUBpvQ==",
+ "dev": true,
"requires": {
- "metro-core": "0.76.7",
+ "metro-core": "0.76.8",
"rimraf": "^3.0.2"
}
},
"metro-cache-key": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.7.tgz",
- "integrity": "sha512-0pecoIzwsD/Whn/Qfa+SDMX2YyasV0ndbcgUFx7w1Ct2sLHClujdhQ4ik6mvQmsaOcnGkIyN0zcceMDjC2+BFQ=="
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.76.8.tgz",
+ "integrity": "sha512-buKQ5xentPig9G6T37Ww/R/bC+/V1MA5xU/D8zjnhlelsrPG6w6LtHUS61ID3zZcMZqYaELWk5UIadIdDsaaLw==",
+ "dev": true
},
"metro-config": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.7.tgz",
- "integrity": "sha512-CFDyNb9bqxZemiChC/gNdXZ7OQkIwmXzkrEXivcXGbgzlt/b2juCv555GWJHyZSlorwnwJfY3uzAFu4A9iRVfg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.76.8.tgz",
+ "integrity": "sha512-SL1lfKB0qGHALcAk2zBqVgQZpazDYvYFGwCK1ikz0S6Y/CM2i2/HwuZN31kpX6z3mqjv/6KvlzaKoTb1otuSAA==",
+ "dev": true,
"requires": {
"connect": "^3.6.5",
"cosmiconfig": "^5.0.5",
"jest-validate": "^29.2.1",
- "metro": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-core": "0.76.7",
- "metro-runtime": "0.76.7"
+ "metro": "0.76.8",
+ "metro-cache": "0.76.8",
+ "metro-core": "0.76.8",
+ "metro-runtime": "0.76.8"
},
"dependencies": {
"cosmiconfig": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
"integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+ "dev": true,
"requires": {
"import-fresh": "^2.0.0",
"is-directory": "^0.3.1",
@@ -72867,6 +74016,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
"integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==",
+ "dev": true,
"requires": {
"caller-path": "^2.0.0",
"resolve-from": "^3.0.0"
@@ -72876,6 +74026,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
"integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
+ "dev": true,
"requires": {
"error-ex": "^1.3.1",
"json-parse-better-errors": "^1.0.1"
@@ -72884,23 +74035,26 @@
"resolve-from": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
- "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw=="
+ "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==",
+ "dev": true
}
}
},
"metro-core": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.7.tgz",
- "integrity": "sha512-0b8KfrwPmwCMW+1V7ZQPkTy2tsEKZjYG9Pu1PTsu463Z9fxX7WaR0fcHFshv+J1CnQSUTwIGGjbNvj1teKe+pw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.76.8.tgz",
+ "integrity": "sha512-sl2QLFI3d1b1XUUGxwzw/KbaXXU/bvFYrSKz6Sg19AdYGWFyzsgZ1VISRIDf+HWm4R/TJXluhWMEkEtZuqi3qA==",
+ "dev": true,
"requires": {
"lodash.throttle": "^4.1.1",
- "metro-resolver": "0.76.7"
+ "metro-resolver": "0.76.8"
}
},
"metro-file-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.7.tgz",
- "integrity": "sha512-s+zEkTcJ4mOJTgEE2ht4jIo1DZfeWreQR3tpT3gDV/Y/0UQ8aJBTv62dE775z0GLsWZApiblAYZsj7ZE8P06nw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.76.8.tgz",
+ "integrity": "sha512-A/xP1YNEVwO1SUV9/YYo6/Y1MmzhL4ZnVgcJC3VmHp/BYVOXVStzgVbWv2wILe56IIMkfXU+jpXrGKKYhFyHVw==",
+ "dev": true,
"requires": {
"anymatch": "^3.0.3",
"debug": "^2.2.0",
@@ -72921,6 +74075,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz",
"integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==",
+ "dev": true,
"requires": {
"@types/istanbul-lib-coverage": "^2.0.0",
"@types/istanbul-reports": "^3.0.0",
@@ -72933,6 +74088,7 @@
"version": "16.0.5",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz",
"integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==",
+ "dev": true,
"requires": {
"@types/yargs-parser": "*"
}
@@ -72941,6 +74097,7 @@
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
"requires": {
"color-convert": "^2.0.1"
}
@@ -72949,6 +74106,7 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
"requires": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -72958,6 +74116,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
"requires": {
"color-name": "~1.1.4"
}
@@ -72965,12 +74124,14 @@
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -72978,17 +74139,20 @@
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true
},
"jest-regex-util": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz",
- "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg=="
+ "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==",
+ "dev": true
},
"jest-util": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz",
"integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==",
+ "dev": true,
"requires": {
"@jest/types": "^27.5.1",
"@types/node": "*",
@@ -73002,6 +74166,7 @@
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "dev": true,
"requires": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -73012,6 +74177,7 @@
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "dev": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -73021,12 +74187,14 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"supports-color": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
"requires": {
"has-flag": "^4.0.0"
}
@@ -73034,9 +74202,10 @@
}
},
"metro-inspector-proxy": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.7.tgz",
- "integrity": "sha512-rNZ/6edTl/1qUekAhAbaFjczMphM50/UjtxiKulo6vqvgn/Mjd9hVqDvVYfAMZXqPvlusD88n38UjVYPkruLSg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-inspector-proxy/-/metro-inspector-proxy-0.76.8.tgz",
+ "integrity": "sha512-Us5o5UEd4Smgn1+TfHX4LvVPoWVo9VsVMn4Ldbk0g5CQx3Gu0ygc/ei2AKPGTwsOZmKxJeACj7yMH2kgxQP/iw==",
+ "dev": true,
"requires": {
"connect": "^3.6.5",
"debug": "^2.2.0",
@@ -73049,6 +74218,7 @@
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
@@ -73059,6 +74229,7 @@
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+ "dev": true,
"requires": {
"ms": "2.0.0"
}
@@ -73066,23 +74237,27 @@
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
+ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+ "dev": true
},
"ws": {
"version": "7.5.9",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
"integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "dev": true,
"requires": {}
},
"y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
- "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true
},
"yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
"requires": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
@@ -73096,30 +74271,34 @@
"yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
- "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true
}
}
},
"metro-minify-terser": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.7.tgz",
- "integrity": "sha512-FQiZGhIxCzhDwK4LxyPMLlq0Tsmla10X7BfNGlYFK0A5IsaVKNJbETyTzhpIwc+YFRT4GkFFwgo0V2N5vxO5HA==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.76.8.tgz",
+ "integrity": "sha512-Orbvg18qXHCrSj1KbaeSDVYRy/gkro2PC7Fy2tDSH1c9RB4aH8tuMOIXnKJE+1SXxBtjWmQ5Yirwkth2DyyEZA==",
+ "dev": true,
"requires": {
"terser": "^5.15.0"
}
},
"metro-minify-uglify": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.7.tgz",
- "integrity": "sha512-FuXIU3j2uNcSvQtPrAJjYWHruPiQ+EpE++J9Z+VznQKEHcIxMMoQZAfIF2IpZSrZYfLOjVFyGMvj41jQMxV1Vw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-minify-uglify/-/metro-minify-uglify-0.76.8.tgz",
+ "integrity": "sha512-6l8/bEvtVaTSuhG1FqS0+Mc8lZ3Bl4RI8SeRIifVLC21eeSDp4CEBUWSGjpFyUDfi6R5dXzYaFnSgMNyfxADiQ==",
+ "dev": true,
"requires": {
"uglify-es": "^3.1.9"
}
},
"metro-react-native-babel-preset": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.7.tgz",
- "integrity": "sha512-R25wq+VOSorAK3hc07NW0SmN8z9S/IR0Us0oGAsBcMZnsgkbOxu77Mduqf+f4is/wnWHc5+9bfiqdLnaMngiVw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.76.8.tgz",
+ "integrity": "sha512-Ptza08GgqzxEdK8apYsjTx2S8WDUlS2ilBlu9DR1CUcHmg4g3kOkFylZroogVAUKtpYQNYwAvdsjmrSdDNtiAg==",
+ "dev": true,
"requires": {
"@babel/core": "^7.20.0",
"@babel/plugin-proposal-async-generator-functions": "^7.0.0",
@@ -73163,31 +74342,34 @@
},
"dependencies": {
"react-refresh": {
- "version": "0.4.3"
+ "version": "0.4.3",
+ "dev": true
}
}
},
"metro-react-native-babel-transformer": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.7.tgz",
- "integrity": "sha512-W6lW3J7y/05ph3c2p3KKJNhH0IdyxdOCbQ5it7aM2MAl0SM4wgKjaV6EYv9b3rHklpV6K3qMH37UKVcjMooWiA==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-react-native-babel-transformer/-/metro-react-native-babel-transformer-0.76.8.tgz",
+ "integrity": "sha512-3h+LfS1WG1PAzhq8QF0kfXjxuXetbY/lgz8vYMQhgrMMp17WM1DNJD0gjx8tOGYbpbBC1qesJ45KMS4o5TA73A==",
+ "dev": true,
"requires": {
"@babel/core": "^7.20.0",
"babel-preset-fbjs": "^3.4.0",
"hermes-parser": "0.12.0",
- "metro-react-native-babel-preset": "0.76.7",
+ "metro-react-native-babel-preset": "0.76.8",
"nullthrows": "^1.1.1"
}
},
"metro-resolver": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.7.tgz",
- "integrity": "sha512-pC0Wgq29HHIHrwz23xxiNgylhI8Rq1V01kQaJ9Kz11zWrIdlrH0ZdnJ7GC6qA0ErROG+cXmJ0rJb8/SW1Zp2IA=="
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.76.8.tgz",
+ "integrity": "sha512-KccOqc10vrzS7ZhG2NSnL2dh3uVydarB7nOhjreQ7C4zyWuiW9XpLC4h47KtGQv3Rnv/NDLJYeDqaJ4/+140HQ==",
+ "dev": true
},
"metro-runtime": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.7.tgz",
- "integrity": "sha512-MuWHubQHymUWBpZLwuKZQgA/qbb35WnDAKPo83rk7JRLIFPvzXSvFaC18voPuzJBt1V98lKQIonh6MiC9gd8Ug==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.76.8.tgz",
+ "integrity": "sha512-XKahvB+iuYJSCr3QqCpROli4B4zASAYpkK+j3a0CJmokxCDNbgyI4Fp88uIL6rNaZfN0Mv35S0b99SdFXIfHjg==",
"requires": {
"@babel/runtime": "^7.0.0",
"react-refresh": "^0.4.0"
@@ -73201,16 +74383,16 @@
}
},
"metro-source-map": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.7.tgz",
- "integrity": "sha512-Prhx7PeRV1LuogT0Kn5VjCuFu9fVD68eefntdWabrksmNY6mXK8pRqzvNJOhTojh6nek+RxBzZeD6MIOOyXS6w==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.76.8.tgz",
+ "integrity": "sha512-Hh0ncPsHPVf6wXQSqJqB3K9Zbudht4aUtNpNXYXSxH+pteWqGAXnjtPsRAnCsCWl38wL0jYF0rJDdMajUI3BDw==",
"requires": {
"@babel/traverse": "^7.20.0",
"@babel/types": "^7.20.0",
"invariant": "^2.2.4",
- "metro-symbolicate": "0.76.7",
+ "metro-symbolicate": "0.76.8",
"nullthrows": "^1.1.1",
- "ob1": "0.76.7",
+ "ob1": "0.76.8",
"source-map": "^0.5.6",
"vlq": "^1.0.0"
},
@@ -73223,12 +74405,12 @@
}
},
"metro-symbolicate": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.7.tgz",
- "integrity": "sha512-p0zWEME5qLSL1bJb93iq+zt5fz3sfVn9xFYzca1TJIpY5MommEaS64Va87lp56O0sfEIvh4307Oaf/ZzRjuLiQ==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.76.8.tgz",
+ "integrity": "sha512-LrRL3uy2VkzrIXVlxoPtqb40J6Bf1mlPNmUQewipc3qfKKFgtPHBackqDy1YL0njDsWopCKcfGtFYLn0PTUn3w==",
"requires": {
"invariant": "^2.2.4",
- "metro-source-map": "0.76.7",
+ "metro-source-map": "0.76.8",
"nullthrows": "^1.1.1",
"source-map": "^0.5.6",
"through2": "^2.0.1",
@@ -73243,9 +74425,10 @@
}
},
"metro-transform-plugins": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.7.tgz",
- "integrity": "sha512-iSmnjVApbdivjuzb88Orb0JHvcEt5veVyFAzxiS5h0QB+zV79w6JCSqZlHCrbNOkOKBED//LqtKbFVakxllnNg==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.76.8.tgz",
+ "integrity": "sha512-PlkGTQNqS51Bx4vuufSQCdSn2R2rt7korzngo+b5GCkeX5pjinPjnO2kNhQ8l+5bO0iUD/WZ9nsM2PGGKIkWFA==",
+ "dev": true,
"requires": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
@@ -73255,21 +74438,22 @@
}
},
"metro-transform-worker": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.7.tgz",
- "integrity": "sha512-cGvELqFMVk9XTC15CMVzrCzcO6sO1lURfcbgjuuPdzaWuD11eEyocvkTX0DPiRjsvgAmicz4XYxVzgYl3MykDw==",
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.76.8.tgz",
+ "integrity": "sha512-mE1fxVAnJKmwwJyDtThildxxos9+DGs9+vTrx2ktSFMEVTtXS/bIv2W6hux1pqivqAfyJpTeACXHk5u2DgGvIQ==",
+ "dev": true,
"requires": {
"@babel/core": "^7.20.0",
"@babel/generator": "^7.20.0",
"@babel/parser": "^7.20.0",
"@babel/types": "^7.20.0",
"babel-preset-fbjs": "^3.4.0",
- "metro": "0.76.7",
- "metro-babel-transformer": "0.76.7",
- "metro-cache": "0.76.7",
- "metro-cache-key": "0.76.7",
- "metro-source-map": "0.76.7",
- "metro-transform-plugins": "0.76.7",
+ "metro": "0.76.8",
+ "metro-babel-transformer": "0.76.8",
+ "metro-cache": "0.76.8",
+ "metro-cache-key": "0.76.8",
+ "metro-source-map": "0.76.8",
+ "metro-transform-plugins": "0.76.8",
"nullthrows": "^1.1.1"
}
},
@@ -74311,9 +75495,9 @@
"dev": true
},
"ob1": {
- "version": "0.76.7",
- "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.7.tgz",
- "integrity": "sha512-BQdRtxxoUNfSoZxqeBGOyuT9nEYSn18xZHwGMb0mMVpn2NBcYbnyKY4BK2LIHRgw33CBGlUmE+KMaNvyTpLLtQ=="
+ "version": "0.76.8",
+ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.76.8.tgz",
+ "integrity": "sha512-dlBkJJV5M/msj9KYA9upc+nUWVwuOFFTbu28X6kZeGwcuW+JxaHSBZ70SYQnk5M+j5JbNLR6yKHmgW4M5E7X5g=="
},
"object-assign": {
"version": "4.1.1"
@@ -75742,6 +76926,14 @@
"scheduler": "^0.22.0"
}
},
+ "react-error-boundary": {
+ "version": "4.0.11",
+ "resolved": "https://registry.npmjs.org/react-error-boundary/-/react-error-boundary-4.0.11.tgz",
+ "integrity": "sha512-U13ul67aP5DOSPNSCWQ/eO0AQEYzEFkVljULQIjMV0KlffTAhxuDoBKdO0pb/JZ8mDhMKFZ9NZi0BmLGUiNphw==",
+ "requires": {
+ "@babel/runtime": "^7.12.5"
+ }
+ },
"react-freeze": {
"version": "1.0.3",
"requires": {}
@@ -75766,20 +76958,20 @@
}
},
"react-native": {
- "version": "0.72.3",
- "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.3.tgz",
- "integrity": "sha512-QqISi+JVmCssNP2FlQ4MWhlc4O/I00MRE1/GClvyZ8h/6kdsyk/sOirkYdZqX3+DrJfI3q+OnyMnsyaXIQ/5tQ==",
+ "version": "0.72.4",
+ "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.72.4.tgz",
+ "integrity": "sha512-+vrObi0wZR+NeqL09KihAAdVlQ9IdplwznJWtYrjnQ4UbCW6rkzZJebRsugwUneSOKNFaHFEo1uKU89HsgtYBg==",
"requires": {
"@jest/create-cache-key-function": "^29.2.1",
- "@react-native-community/cli": "11.3.5",
- "@react-native-community/cli-platform-android": "11.3.5",
- "@react-native-community/cli-platform-ios": "11.3.5",
+ "@react-native-community/cli": "11.3.6",
+ "@react-native-community/cli-platform-android": "11.3.6",
+ "@react-native-community/cli-platform-ios": "11.3.6",
"@react-native/assets-registry": "^0.72.0",
"@react-native/codegen": "^0.72.6",
"@react-native/gradle-plugin": "^0.72.11",
"@react-native/js-polyfills": "^0.72.1",
"@react-native/normalize-colors": "^0.72.0",
- "@react-native/virtualized-lists": "^0.72.6",
+ "@react-native/virtualized-lists": "^0.72.8",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"base64-js": "^1.1.2",
@@ -75790,8 +76982,8 @@
"jest-environment-node": "^29.2.1",
"jsc-android": "^250231.0.0",
"memoize-one": "^5.0.0",
- "metro-runtime": "0.76.7",
- "metro-source-map": "0.76.7",
+ "metro-runtime": "0.76.8",
+ "metro-source-map": "0.76.8",
"mkdirp": "^0.5.1",
"nullthrows": "^1.1.1",
"pretty-format": "^26.5.2",
@@ -76017,9 +77209,9 @@
}
},
"react-native-google-places-autocomplete": {
- "version": "git+ssh://git@github.com/Expensify/react-native-google-places-autocomplete.git#ee87343c3e827ff7818abc71b6bb04fcc1f120e0",
- "integrity": "sha512-OJWCz4Epj1p8tyNImWNykAqpd/X1MkNCFPY0dSbgiTJGbW4J5T4bC0PIUQ+ExjxWpWjcFaielTLdoSz0HfeIpw==",
- "from": "react-native-google-places-autocomplete@git+https://github.com/Expensify/react-native-google-places-autocomplete.git#ee87343c3e827ff7818abc71b6bb04fcc1f120e0",
+ "version": "git+ssh://git@github.com/Expensify/react-native-google-places-autocomplete.git#cef3ac29d9501091453136e1219e24c4ec9f9d76",
+ "integrity": "sha512-2z3ED8jOXasPTzBqvPwpG10LQsBArTRsYszmoz+TfqbgZrSBmP3c8rhaC//lx6Pvfs2r+KYWqJUrLf4mbCrjZw==",
+ "from": "react-native-google-places-autocomplete@git+https://github.com/Expensify/react-native-google-places-autocomplete.git#cef3ac29d9501091453136e1219e24c4ec9f9d76",
"requires": {
"lodash.debounce": "^4.0.8",
"prop-types": "^15.7.2",
@@ -76073,9 +77265,9 @@
}
},
"react-native-onyx": {
- "version": "1.0.77",
- "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.77.tgz",
- "integrity": "sha512-HmeS1Pz/BkKNbYuhWULC9I0VRBDt8yadG0ZFIW6wuZ+VajhjD960qh7Il1+XzEBI6Vb4d7BZkPcad87ad1IEOQ==",
+ "version": "1.0.84",
+ "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.84.tgz",
+ "integrity": "sha512-qQ+o+qS5ucZLbKbG5kI0UsC42N4h1Pprg/1D7PqjDeVanS3iUv33rT4fbrHuar77g0DSTA1/M8bC2WmYrShS9A==",
"requires": {
"ascii-table": "0.0.9",
"fast-equals": "^4.0.3",
@@ -79035,7 +80227,9 @@
"dev": true
},
"throat": {
- "version": "5.0.0"
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
+ "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA=="
},
"throttle-debounce": {
"version": "3.0.1",
@@ -79939,7 +81133,9 @@
"version": "1.2.8"
},
"vlq": {
- "version": "1.0.1"
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz",
+ "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w=="
},
"vm-browserify": {
"version": "1.1.2"
diff --git a/package.json b/package.json
index 0605d44d89fc..44b936c8c588 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.71-5",
+ "version": "1.3.72-9",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
@@ -112,7 +112,8 @@
"react-content-loader": "^6.1.0",
"react-dom": "18.1.0",
"react-map-gl": "^7.1.3",
- "react-native": "0.72.3",
+ "react-error-boundary": "^4.0.11",
+ "react-native": "0.72.4",
"react-native-blob-util": "^0.17.3",
"react-native-collapsible": "^1.6.0",
"react-native-config": "^1.4.5",
@@ -122,7 +123,7 @@
"react-native-fast-image": "^8.6.3",
"react-native-fs": "^2.20.0",
"react-native-gesture-handler": "2.12.0",
- "react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#ee87343c3e827ff7818abc71b6bb04fcc1f120e0",
+ "react-native-google-places-autocomplete": "git+https://github.com/Expensify/react-native-google-places-autocomplete.git#cef3ac29d9501091453136e1219e24c4ec9f9d76",
"react-native-haptic-feedback": "^1.13.0",
"react-native-image-pan-zoom": "^2.1.12",
"react-native-image-picker": "^5.1.0",
@@ -131,7 +132,7 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "1.0.77",
+ "react-native-onyx": "1.0.84",
"react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.7.1",
"react-native-performance": "^5.1.0",
@@ -180,7 +181,7 @@
"@octokit/plugin-paginate-rest": "3.1.0",
"@octokit/plugin-throttling": "4.1.0",
"@react-native-community/eslint-config": "3.0.0",
- "@react-native/metro-config": "^0.72.9",
+ "@react-native/metro-config": "^0.72.11",
"@react-navigation/devtools": "^6.0.10",
"@storybook/addon-a11y": "^6.5.9",
"@storybook/addon-essentials": "^7.0.0",
@@ -245,7 +246,7 @@
"jest-circus": "29.4.1",
"jest-cli": "29.4.1",
"jest-environment-jsdom": "^29.4.1",
- "metro-react-native-babel-preset": "0.76.7",
+ "metro-react-native-babel-preset": "0.76.8",
"mock-fs": "^4.13.0",
"onchange": "^7.1.0",
"portfinder": "^1.0.28",
diff --git a/patches/react-native+0.72.3+001+initial.patch b/patches/react-native+0.72.4+001+initial.patch
similarity index 100%
rename from patches/react-native+0.72.3+001+initial.patch
rename to patches/react-native+0.72.4+001+initial.patch
diff --git a/patches/react-native+0.72.3+002+NumberOfLines.patch b/patches/react-native+0.72.4+002+NumberOfLines.patch
similarity index 97%
rename from patches/react-native+0.72.3+002+NumberOfLines.patch
rename to patches/react-native+0.72.4+002+NumberOfLines.patch
index 7d773297cb5f..75422f84708e 100644
--- a/patches/react-native+0.72.3+002+NumberOfLines.patch
+++ b/patches/react-native+0.72.4+002+NumberOfLines.patch
@@ -30,10 +30,10 @@ index 6f69329..d531bee 100644
maxLength: true,
autoCapitalize: true,
diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts b/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
-index ff029fb..0835135 100644
+index 8badb2a..b19f197 100644
--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.d.ts
-@@ -338,12 +338,6 @@ export interface TextInputAndroidProps {
+@@ -347,12 +347,6 @@ export interface TextInputAndroidProps {
*/
inlineImagePadding?: number | undefined;
@@ -46,7 +46,7 @@ index ff029fb..0835135 100644
/**
* Sets the return key to the label. Use it instead of `returnKeyType`.
* @platform android
-@@ -654,11 +648,29 @@ export interface TextInputProps
+@@ -663,11 +657,30 @@ export interface TextInputProps
*/
maxLength?: number | undefined;
@@ -72,6 +72,7 @@ index ff029fb..0835135 100644
+ * Use it with multiline set to true to be able to fill the lines.
+ */
+ rows?: number | undefined;
++
+
/**
* Callback that is called when the text input is blurred
@@ -147,10 +148,10 @@ index 7ed4579..b1d994e 100644
* If `true`, the text input obscures the text entered so that sensitive text
* like passwords stay secure. The default value is `false`. Does not work with 'multiline={true}'.
diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
-index df89097..3b223ec 100644
+index 2127191..542fc06 100644
--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
-@@ -387,7 +387,6 @@ type AndroidProps = $ReadOnly<{|
+@@ -390,7 +390,6 @@ type AndroidProps = $ReadOnly<{|
/**
* Sets the number of lines for a `TextInput`. Use it with multiline set to
* `true` to be able to fill the lines.
@@ -158,7 +159,7 @@ index df89097..3b223ec 100644
*/
numberOfLines?: ?number,
-@@ -400,10 +399,14 @@ type AndroidProps = $ReadOnly<{|
+@@ -403,10 +402,14 @@ type AndroidProps = $ReadOnly<{|
/**
* Sets the number of rows for a `TextInput`. Use it with multiline set to
* `true` to be able to fill the lines.
@@ -174,7 +175,7 @@ index df89097..3b223ec 100644
/**
* When `false`, it will prevent the soft keyboard from showing when the field is focused.
* Defaults to `true`.
-@@ -1066,6 +1069,9 @@ function InternalTextInput(props: Props): React.Node {
+@@ -1069,6 +1072,9 @@ function InternalTextInput(props: Props): React.Node {
accessibilityState,
id,
tabIndex,
@@ -184,7 +185,7 @@ index df89097..3b223ec 100644
selection: propsSelection,
...otherProps
} = props;
-@@ -1422,6 +1428,8 @@ function InternalTextInput(props: Props): React.Node {
+@@ -1427,6 +1433,8 @@ function InternalTextInput(props: Props): React.Node {
focusable={tabIndex !== undefined ? !tabIndex : focusable}
mostRecentEventCount={mostRecentEventCount}
nativeID={id ?? props.nativeID}
@@ -193,7 +194,7 @@ index df89097..3b223ec 100644
onBlur={_onBlur}
onKeyPressSync={props.unstable_onKeyPressSync}
onChange={_onChange}
-@@ -1477,6 +1485,7 @@ function InternalTextInput(props: Props): React.Node {
+@@ -1482,6 +1490,7 @@ function InternalTextInput(props: Props): React.Node {
mostRecentEventCount={mostRecentEventCount}
nativeID={id ?? props.nativeID}
numberOfLines={props.rows ?? props.numberOfLines}
@@ -549,7 +550,7 @@ index 190bc27..c2bcdc1 100644
: mEllipsizeLocation;
setEllipsize(ellipsizeLocation);
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java
-index 561a2d0..017be13 100644
+index 561a2d0..9409cfc 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.java
@@ -18,6 +18,7 @@ import android.text.SpannableStringBuilder;
@@ -568,7 +569,7 @@ index 561a2d0..017be13 100644
private static final LruCache sSpannableCache =
new LruCache<>(spannableCacheSize);
private static final ConcurrentHashMap sTagToSpannableCache =
-@@ -385,6 +387,47 @@ public class TextLayoutManager {
+@@ -385,6 +387,48 @@ public class TextLayoutManager {
? paragraphAttributes.getInt(MAXIMUM_NUMBER_OF_LINES_KEY)
: UNSET;
@@ -612,12 +613,13 @@ index 561a2d0..017be13 100644
+ if (numberOfLines != UNSET && numberOfLines != 0) {
+ maximumNumberOfLines = numberOfLines;
+ }
++
+
int calculatedLineCount =
maximumNumberOfLines == UNSET || maximumNumberOfLines == 0
? layout.getLineCount()
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java
-index 0d118f0..f29f069 100644
+index 0d118f0..0ae44b7 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManagerMapBuffer.java
@@ -18,6 +18,7 @@ import android.text.SpannableStringBuilder;
@@ -636,7 +638,7 @@ index 0d118f0..f29f069 100644
private static final boolean ENABLE_MEASURE_LOGGING = ReactBuildConfig.DEBUG && false;
-@@ -399,6 +401,46 @@ public class TextLayoutManagerMapBuffer {
+@@ -399,6 +401,47 @@ public class TextLayoutManagerMapBuffer {
? paragraphAttributes.getInt(PA_KEY_MAX_NUMBER_OF_LINES)
: UNSET;
@@ -679,15 +681,16 @@ index 0d118f0..f29f069 100644
+ if (numberOfLines != UNSET && numberOfLines != 0) {
+ maximumNumberOfLines = numberOfLines;
+ }
++
+
int calculatedLineCount =
maximumNumberOfLines == UNSET || maximumNumberOfLines == 0
? layout.getLineCount()
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
-index 1b5e0f4..67d0b73 100644
+index ced37be..ef2f321 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java
-@@ -483,7 +483,13 @@ public class ReactEditText extends AppCompatEditText
+@@ -548,7 +548,13 @@ public class ReactEditText extends AppCompatEditText
* href='https://android.googlesource.com/platform/frameworks/base/+/jb-release/core/java/android/widget/TextView.java'>TextView.java}
*/
if (isMultiline()) {
@@ -807,10 +810,10 @@ index f5f87c6..b7d1e90 100644
attributes.ellipsizeMode,
attributes.textBreakStrategy,
diff --git a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h
-index 8687b89..26379f4 100644
+index 8687b89..eab75f4 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h
+++ b/node_modules/react-native/ReactCommon/react/renderer/attributedstring/conversions.h
-@@ -835,12 +835,18 @@ inline ParagraphAttributes convertRawProp(
+@@ -835,10 +835,16 @@ inline ParagraphAttributes convertRawProp(
ParagraphAttributes const &defaultParagraphAttributes) {
auto paragraphAttributes = ParagraphAttributes{};
@@ -819,19 +822,15 @@ index 8687b89..26379f4 100644
context,
rawProps,
"numberOfLines",
-- sourceParagraphAttributes.maximumNumberOfLines,
-- defaultParagraphAttributes.maximumNumberOfLines);
+ sourceParagraphAttributes.numberOfLines,
+ defaultParagraphAttributes.numberOfLines);
+ paragraphAttributes.maximumNumberOfLines = convertRawProp(
-+ context,
-+ rawProps,
-+ "maximumNumberOfLines",
-+ sourceParagraphAttributes.maximumNumberOfLines,
-+ defaultParagraphAttributes.maximumNumberOfLines);
++ context,
++ rawProps,
++ "maximumNumberOfLines",
+ sourceParagraphAttributes.maximumNumberOfLines,
+ defaultParagraphAttributes.maximumNumberOfLines);
paragraphAttributes.ellipsizeMode = convertRawProp(
- context,
- rawProps,
@@ -913,6 +919,7 @@ inline std::string toString(AttributedString::Range const &range) {
inline folly::dynamic toDynamic(
const ParagraphAttributes ¶graphAttributes) {
@@ -853,7 +852,7 @@ index 8687b89..26379f4 100644
PA_KEY_HYPHENATION_FREQUENCY,
toString(paragraphAttributes.android_hyphenationFrequency));
+ builder.putInt(
-+ PA_KEY_NUMBER_OF_LINES, paragraphAttributes.numberOfLines);
++ PA_KEY_NUMBER_OF_LINES, paragraphAttributes.numberOfLines);
return builder.build();
}
@@ -914,15 +913,15 @@ index ba39ebb..ead28e3 100644
std::string textBreakStrategy{};
SharedColor underlineColorAndroid{};
diff --git a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
-index 368c334..2a98ad0 100644
+index 368c334..a1bb33e 100644
--- a/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
+++ b/node_modules/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/ios/react/renderer/textlayoutmanager/RCTTextLayoutManager.mm
-@@ -244,26 +244,50 @@ - (void)getRectWithAttributedString:(AttributedString)attributedString
+@@ -244,26 +244,51 @@ - (void)getRectWithAttributedString:(AttributedString)attributedString
#pragma mark - Private
-- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)attributedString
-+- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)inputAttributedString
+++- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)inputAttributedString
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
size:(CGSize)size
{
@@ -950,7 +949,6 @@ index 368c334..2a98ad0 100644
- ? RCTNSLineBreakModeFromEllipsizeMode(paragraphAttributes.ellipsizeMode)
- : NSLineBreakByClipping;
- textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
-+
+ [attributedString insertAttributedString:[[NSAttributedString alloc] initWithString:newLines attributes:attributesOfFirstCharacter] atIndex:0];
+ }
+
@@ -959,7 +957,7 @@ index 368c334..2a98ad0 100644
NSLayoutManager *layoutManager = [NSLayoutManager new];
layoutManager.usesFontLeading = NO;
[layoutManager addTextContainer:textContainer];
--
+
- NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedString];
+ NSTextStorage *textStorage = [NSTextStorage new];
@@ -973,6 +971,7 @@ index 368c334..2a98ad0 100644
+ textContainer.maximumNumberOfLines = paragraphAttributes.maximumNumberOfLines;
+
+ [textStorage replaceCharactersInRange:(NSRange){0, textStorage.length} withAttributedString:attributedString];
++
+
if (paragraphAttributes.adjustsFontSizeToFit) {
CGFloat minimumFontSize = !isnan(paragraphAttributes.minimumFontSize) ? paragraphAttributes.minimumFontSize : 4.0;
diff --git a/patches/react-native+0.72.3+003+VerticalScrollBarPosition.patch b/patches/react-native+0.72.4+003+VerticalScrollBarPosition.patch
similarity index 76%
rename from patches/react-native+0.72.3+003+VerticalScrollBarPosition.patch
rename to patches/react-native+0.72.4+003+VerticalScrollBarPosition.patch
index 1cf8f6de54fb..e6ed0d4f79a3 100644
--- a/patches/react-native+0.72.3+003+VerticalScrollBarPosition.patch
+++ b/patches/react-native+0.72.4+003+VerticalScrollBarPosition.patch
@@ -1,12 +1,11 @@
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
-index 46e0ccf..53293a4 100644
+index 33658e7..31c20c0 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/scroll/ReactScrollViewManager.java
-@@ -379,4 +379,15 @@ public class ReactScrollViewManager extends ViewGroupManager
- public void setScrollEventThrottle(ReactScrollView view, int scrollEventThrottle) {
+@@ -381,6 +381,17 @@ public class ReactScrollViewManager extends ViewGroupManager
view.setScrollEventThrottle(scrollEventThrottle);
}
-+
+
+ @ReactProp(name = "verticalScrollbarPosition")
+ public void setVerticalScrollbarPosition(ReactScrollView view, String position) {
+ if ("right".equals(position)) {
@@ -17,4 +16,7 @@ index 46e0ccf..53293a4 100644
+ view.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_DEFAULT);
+ }
+ }
- }
++
+ @ReactProp(name = "isInvertedVirtualizedList")
+ public void setIsInvertedVirtualizedList(ReactScrollView view, boolean applyFix) {
+ // Usually when inverting the scroll view we are using scaleY: -1 on the list
diff --git a/patches/react-native+0.72.3+004+ModalKeyboardFlashing.patch b/patches/react-native+0.72.4+004+ModalKeyboardFlashing.patch
similarity index 100%
rename from patches/react-native+0.72.3+004+ModalKeyboardFlashing.patch
rename to patches/react-native+0.72.4+004+ModalKeyboardFlashing.patch
diff --git a/patches/react-native-image-picker+5.1.0.patch b/patches/react-native-image-picker+5.1.0.patch
new file mode 100644
index 000000000000..0defc430e669
--- /dev/null
+++ b/patches/react-native-image-picker+5.1.0.patch
@@ -0,0 +1,133 @@
+diff --git a/node_modules/react-native-image-picker/android/src/main/java/com/imagepicker/ImagePickerModuleImpl.java b/node_modules/react-native-image-picker/android/src/main/java/com/imagepicker/ImagePickerModuleImpl.java
+index 89b69a8..d86ab1e 100644
+--- a/node_modules/react-native-image-picker/android/src/main/java/com/imagepicker/ImagePickerModuleImpl.java
++++ b/node_modules/react-native-image-picker/android/src/main/java/com/imagepicker/ImagePickerModuleImpl.java
+@@ -29,6 +29,120 @@ public class ImagePickerModuleImpl implements ActivityEventListener {
+ public static final int REQUEST_LAUNCH_VIDEO_CAPTURE = 13002;
+ public static final int REQUEST_LAUNCH_LIBRARY = 13003;
+
++ // Prevent svg images from being selected as they are not supported (Image component does not support them)
++ // and also because iOS does not allow them to be selected (for consistency).
++ // Since, we can't exclude a mime type, we instead allow all image mime types except 'image/svg+xml'.
++ // Image mime types are generated by merging the Android image mime type support and the IANA media-types lists.
++ // https://android.googlesource.com/platform/external/mime-support/+/main/mime.types#636
++ // https://www.iana.org/assignments/media-types/media-types.xhtml#image
++ private static final String[] ALLOWED_IMAGE_MIME_TYPES = {
++ "image/aces",
++ "image/apng",
++ "image/avci",
++ "image/avcs",
++ "image/avif",
++ "image/bmp",
++ "image/cgm",
++ "image/dicom-rle",
++ "image/dpx",
++ "image/emf",
++ "image/example",
++ "image/fits",
++ "image/g3fax",
++ "image/gif",
++ "image/heic-sequence",
++ "image/heic",
++ "image/heif-sequence",
++ "image/heif",
++ "image/hej2k",
++ "image/hsj2",
++ "image/ief",
++ "image/j2c",
++ "image/jls",
++ "image/jp2",
++ "image/jpeg",
++ "image/jph",
++ "image/jphc",
++ "image/jpm",
++ "image/jpx",
++ "image/jxr",
++ "image/jxrA",
++ "image/jxrS",
++ "image/jxs",
++ "image/jxsc",
++ "image/jxsi",
++ "image/jxss",
++ "image/ktx",
++ "image/ktx2",
++ "image/naplps",
++ "image/pcx",
++ "image/png",
++ "image/prs.btif",
++ "image/prs.pti",
++ "image/pwg-raster",
++ // "image/svg+xml",
++ "image/t38",
++ "image/tiff-fx",
++ "image/tiff",
++ "image/vnd.adobe.photoshop",
++ "image/vnd.airzip.accelerator.azv",
++ "image/vnd.cns.inf2",
++ "image/vnd.dece.graphic",
++ "image/vnd.djvu",
++ "image/vnd.dvb.subtitle",
++ "image/vnd.dwg",
++ "image/vnd.dxf",
++ "image/vnd.fastbidsheet",
++ "image/vnd.fpx",
++ "image/vnd.fst",
++ "image/vnd.fujixerox.edmics-mmr",
++ "image/vnd.fujixerox.edmics-rlc",
++ "image/vnd.globalgraphics.pgb",
++ "image/vnd.microsoft.icon",
++ "image/vnd.mix",
++ "image/vnd.mozilla.apng",
++ "image/vnd.ms-modi",
++ "image/vnd.net-fpx",
++ "image/vnd.pco.b16",
++ "image/vnd.radiance",
++ "image/vnd.sealed.png",
++ "image/vnd.sealedmedia.softseal.gif",
++ "image/vnd.sealedmedia.softseal.jpg",
++ "image/vnd.svf",
++ "image/vnd.tencent.tap",
++ "image/vnd.valve.source.texture",
++ "image/vnd.wap.wbmp",
++ "image/vnd.xiff",
++ "image/vnd.zbrush.pcx",
++ "image/webp",
++ "image/wmf",
++ "image/x-canon-cr2",
++ "image/x-canon-crw",
++ "image/x-cmu-raster",
++ "image/x-coreldraw",
++ "image/x-coreldrawpattern",
++ "image/x-coreldrawtemplate",
++ "image/x-corelphotopaint",
++ "image/x-emf",
++ "image/x-epson-erf",
++ "image/x-icon",
++ "image/x-jg",
++ "image/x-jng",
++ "image/x-ms-bmp",
++ "image/x-nikon-nef",
++ "image/x-olympus-orf",
++ "image/x-photoshop",
++ "image/x-portable-anymap",
++ "image/x-portable-bitmap",
++ "image/x-portable-graymap",
++ "image/x-portable-pixmap",
++ "image/x-rgb",
++ "image/x-wmf",
++ "image/x-xbitmap",
++ "image/x-xpixmap",
++ "image/x-xwindowdump",
++ };
++
+ private Uri fileUri;
+
+ private ReactApplicationContext reactContext;
+@@ -148,6 +262,7 @@ public class ImagePickerModuleImpl implements ActivityEventListener {
+
+ if (isPhoto) {
+ libraryIntent.setType("image/*");
++ libraryIntent.putExtra(Intent.EXTRA_MIME_TYPES, this.ALLOWED_IMAGE_MIME_TYPES);
+ } else if (isVideo) {
+ libraryIntent.setType("video/*");
+ } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
diff --git a/src/CONST.ts b/src/CONST.ts
index 762186439cec..dcd5ac1a8db7 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -757,6 +757,9 @@ const CONST = {
// 6 numeric digits
VALIDATE_CODE_REGEX_STRING: /^\d{6}$/,
+ // 8 alphanumeric characters
+ RECOVERY_CODE_REGEX_STRING: /^[a-zA-Z0-9]{8}$/,
+
// The server has a WAF (Web Application Firewall) which will strip out HTML/XML tags using this regex pattern.
// It's copied here so that the same regex pattern can be used in form validations to be consistent with the server.
VALIDATE_FOR_HTML_TAG_REGEX: /<([^>\s]+)(?:[^>]*?)>/g,
@@ -792,6 +795,10 @@ const CONST = {
INVISIBLE_CODEPOINTS: ['fe0f', '200d', '2066'],
+ UNICODE: {
+ LTR: '\u2066',
+ },
+
TOOLTIP_MAX_LINES: 3,
LOGIN_TYPE: {
@@ -802,6 +809,8 @@ const CONST = {
MAGIC_CODE_LENGTH: 6,
MAGIC_CODE_EMPTY_CHAR: ' ',
+ RECOVERY_CODE_LENGTH: 8,
+
KEYBOARD_TYPE: {
PHONE_PAD: 'phone-pad',
NUMBER_PAD: 'number-pad',
@@ -1026,7 +1035,6 @@ const CONST = {
},
PAYMENT_METHODS: {
- PAYPAL: 'payPalMe',
DEBIT_CARD: 'debitCard',
BANK_ACCOUNT: 'bankAccount',
},
@@ -1042,7 +1050,6 @@ const CONST = {
PAYMENT_TYPE: {
ELSEWHERE: 'Elsewhere',
EXPENSIFY: 'Expensify',
- PAYPAL_ME: 'PayPal.me',
VBBA: 'ACH',
},
MONEY_REQUEST_TYPE: {
@@ -1156,6 +1163,7 @@ const CONST = {
},
AVATAR_SIZE: {
+ XLARGE: 'xlarge',
LARGE: 'large',
MEDIUM: 'medium',
DEFAULT: 'default',
@@ -1201,7 +1209,6 @@ const CONST = {
CARD_NUMBER: /^[0-9]{15,16}$/,
CARD_SECURITY_CODE: /^[0-9]{3,4}$/,
CARD_EXPIRATION_DATE: /^(0[1-9]|1[0-2])([^0-9])?([0-9]{4}|([0-9]{2}))$/,
- PAYPAL_ME_USERNAME: /^[a-zA-Z0-9]{1,20}$/,
ROOM_NAME: /^#[a-z0-9à-ÿ-]{1,80}$/,
// eslint-disable-next-line max-len, no-misleading-character-class
@@ -1305,9 +1312,9 @@ const CONST = {
},
// Auth limit is 60k for the column but we store edits and other metadata along the html so let's use a lower limit to accommodate for it.
- MAX_COMMENT_LENGTH: 15000,
+ MAX_COMMENT_LENGTH: 10000,
- // Furthermore, applying markup is very resource-consuming, so let's set a slightly lower limit for that
+ // Use the same value as MAX_COMMENT_LENGTH to ensure the entire comment is parsed. Note that applying markup is very resource-consuming.
MAX_MARKUP_LENGTH: 10000,
MAX_THREAD_REPLIES_PREVIEW: 99,
@@ -1351,6 +1358,7 @@ const CONST = {
DATE: 'date',
DESCRIPTION: 'description',
MERCHANT: 'merchant',
+ RECEIPT: 'receipt',
},
FOOTER: {
EXPENSE_MANAGEMENT_URL: `${USE_EXPENSIFY_URL}/expense-management`,
@@ -2532,32 +2540,6 @@ const CONST = {
SEARCH_ISSUES: 'https://github.com/Expensify/App/issues',
},
- PAYPAL_SUPPORTED_CURRENCIES: [
- 'AUD',
- 'BRL',
- 'CAD',
- 'CZK',
- 'DKK',
- 'EUR',
- 'HKD',
- 'HUF',
- 'ILS',
- 'JPY',
- 'MYR',
- 'MXN',
- 'TWD',
- 'NZD',
- 'NOK',
- 'PHP',
- 'PLN',
- 'GBP',
- 'RUB',
- 'SGD',
- 'SEK',
- 'CHF',
- 'THB',
- 'USD',
- ],
CONCIERGE_TRAVEL_URL: 'https://community.expensify.com/discussion/7066/introducing-concierge-travel',
SCREEN_READER_STATES: {
ALL: 'all',
@@ -2657,6 +2639,7 @@ const CONST = {
INDENTS: ' ',
PARENT_CHILD_SEPARATOR: ': ',
CATEGORY_LIST_THRESHOLD: 8,
+ TAG_LIST_THRESHOLD: 8,
DEMO_PAGES: {
SAASTR: 'SaaStrDemoSetup',
SBE: 'SbeDemoSetup',
@@ -2672,6 +2655,15 @@ const CONST = {
HTTPS: 'https',
PUSHER: 'pusher',
},
+ EVENTS: {
+ SCROLLING: 'scrolling',
+ },
+ HORIZONTAL_SPACER: {
+ DEFAULT_BORDER_BOTTOM_WIDTH: 1,
+ DEFAULT_MARGIN_VERTICAL: 8,
+ HIDDEN_MARGIN_VERTICAL: 0,
+ HIDDEN_BORDER_BOTTOM_WIDTH: 0,
+ },
} as const;
export default CONST;
diff --git a/src/Expensify.js b/src/Expensify.js
index fba65e42c06c..9e6ae1ff27b4 100644
--- a/src/Expensify.js
+++ b/src/Expensify.js
@@ -99,7 +99,9 @@ function Expensify(props) {
const [hasAttemptedToOpenPublicRoom, setAttemptedToOpenPublicRoom] = useState(false);
useEffect(() => {
- if (props.isCheckingPublicRoom) return;
+ if (props.isCheckingPublicRoom) {
+ return;
+ }
setAttemptedToOpenPublicRoom(true);
}, [props.isCheckingPublicRoom]);
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 8a6e40fb1a04..7f7292e348a6 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -1,4 +1,5 @@
import {ValueOf} from 'type-fest';
+import {OnyxUpdate} from 'react-native-onyx';
import DeepValueOf from './types/utils/DeepValueOf';
import * as OnyxTypes from './types/onyx';
import CONST from './CONST';
@@ -88,9 +89,6 @@ const ONYXKEYS = {
BETAS: 'betas',
/** NVP keys
- * Contains the user's payPalMe data */
- PAYPAL: 'paypal',
-
/** Contains the user preference for the LHN priority mode */
NVP_PRIORITY_MODE: 'nvp_priorityMode',
@@ -172,6 +170,9 @@ const ONYXKEYS = {
/** Is report data loading? */
IS_LOADING_REPORT_DATA: 'isLoadingReportData',
+ /** Is report data loading? */
+ IS_LOADING_APP: 'isLoadingApp',
+
/** Is Keyboard shortcuts modal open? */
IS_SHORTCUTS_MODAL_OPEN: 'isShortcutsModalOpen',
@@ -281,7 +282,6 @@ const ONYXKEYS = {
MONEY_REQUEST_AMOUNT_FORM: 'moneyRequestAmountForm',
MONEY_REQUEST_DATE_FORM: 'moneyRequestCreatedForm',
NEW_CONTACT_METHOD_FORM: 'newContactMethodForm',
- PAYPAL_FORM: 'payPalForm',
WAYPOINT_FORM: 'waypointForm',
WAYPOINT_FORM_DRAFT: 'waypointFormDraft',
SETTINGS_STATUS_SET_FORM: 'settingsStatusSetForm',
@@ -305,7 +305,7 @@ type OnyxValues = {
[ONYXKEYS.DEVICE_ID]: string;
[ONYXKEYS.IS_SIDEBAR_LOADED]: boolean;
[ONYXKEYS.PERSISTED_REQUESTS]: OnyxTypes.Request[];
- [ONYXKEYS.QUEUED_ONYX_UPDATES]: OnyxTypes.QueuedOnyxUpdates;
+ [ONYXKEYS.QUEUED_ONYX_UPDATES]: OnyxUpdate[];
[ONYXKEYS.CURRENT_DATE]: string;
[ONYXKEYS.CREDENTIALS]: OnyxTypes.Credentials;
[ONYXKEYS.IOU]: OnyxTypes.IOU;
@@ -324,7 +324,6 @@ type OnyxValues = {
[ONYXKEYS.LOGIN_LIST]: OnyxTypes.Login;
[ONYXKEYS.SESSION]: OnyxTypes.Session;
[ONYXKEYS.BETAS]: OnyxTypes.Beta[];
- [ONYXKEYS.PAYPAL]: OnyxTypes.Paypal;
[ONYXKEYS.NVP_PRIORITY_MODE]: ValueOf;
[ONYXKEYS.NVP_BLOCKED_FROM_CONCIERGE]: OnyxTypes.BlockedFromConcierge;
[ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string;
@@ -363,7 +362,6 @@ type OnyxValues = {
[ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID]: string;
[ONYXKEYS.PREFERRED_THEME]: ValueOf;
[ONYXKEYS.IS_USING_MEMORY_ONLY_KEYS]: boolean;
- [ONYXKEYS.RECEIPT_MODAL]: OnyxTypes.ReceiptModal;
[ONYXKEYS.MAPBOX_ACCESS_TOKEN]: OnyxTypes.MapboxAccessToken;
[ONYXKEYS.ONYX_UPDATES_FROM_SERVER]: OnyxTypes.OnyxUpdatesFromServer;
[ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT]: number;
@@ -416,7 +414,6 @@ type OnyxValues = {
[ONYXKEYS.FORMS.MONEY_REQUEST_DATE_FORM]: OnyxTypes.Form;
[ONYXKEYS.FORMS.MONEY_REQUEST_DATE_FORM]: OnyxTypes.Form;
[ONYXKEYS.FORMS.NEW_CONTACT_METHOD_FORM]: OnyxTypes.Form;
- [ONYXKEYS.FORMS.PAYPAL_FORM]: OnyxTypes.Form;
[ONYXKEYS.FORMS.WAYPOINT_FORM]: OnyxTypes.Form;
[ONYXKEYS.FORMS.WAYPOINT_FORM_DRAFT]: OnyxTypes.Form;
[ONYXKEYS.FORMS.SETTINGS_STATUS_SET_FORM]: OnyxTypes.Form;
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 9459708c893b..2c37116db395 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -48,7 +48,6 @@ export default {
SETTINGS_ABOUT: 'settings/about',
SETTINGS_APP_DOWNLOAD_LINKS: 'settings/about/app-download-links',
SETTINGS_WALLET: 'settings/wallet',
- SETTINGS_ADD_PAYPAL_ME: 'settings/wallet/add-paypal-me',
SETTINGS_ADD_DEBIT_CARD: 'settings/wallet/add-debit-card',
SETTINGS_ADD_BANK_ACCOUNT: 'settings/wallet/add-bank-account',
SETTINGS_ENABLE_PAYMENTS: 'settings/wallet/enable-payments',
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 47935e117e99..eb125a43c239 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -12,8 +12,14 @@ export default {
VALIDATE_LOGIN: 'ValidateLogin',
CONCIERGE: 'Concierge',
SETTINGS: {
+ ROOT: 'Settings_Root',
PREFERENCES: 'Settings_Preferences',
WORKSPACES: 'Settings_Workspaces',
+ SECURITY: 'Settings_Security',
+ STATUS: 'Settings_Status',
+ },
+ SAVE_THE_WORLD: {
+ ROOT: 'SaveTheWorld_Root',
},
SIGN_IN_WITH_APPLE_DESKTOP: 'AppleSignInDesktop',
SIGN_IN_WITH_GOOGLE_DESKTOP: 'GoogleSignInDesktop',
diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js
index 7f1544a758f4..399247a35676 100644
--- a/src/components/AddPaymentMethodMenu.js
+++ b/src/components/AddPaymentMethodMenu.js
@@ -10,7 +10,6 @@ import withWindowDimensions from './withWindowDimensions';
import Permissions from '../libs/Permissions';
import PopoverMenu from './PopoverMenu';
import refPropTypes from './refPropTypes';
-import paypalMeDataPropTypes from './paypalMeDataPropTypes';
const propTypes = {
/** Should the component be visible? */
@@ -25,12 +24,6 @@ const propTypes = {
vertical: PropTypes.number,
}),
- /** Account details for PayPal.Me */
- payPalMeData: paypalMeDataPropTypes,
-
- /** Should we show the Paypal option */
- shouldShowPaypal: PropTypes.bool,
-
/** List of betas available to current user */
betas: PropTypes.arrayOf(PropTypes.string),
@@ -42,8 +35,6 @@ const propTypes = {
const defaultProps = {
anchorPosition: {},
- payPalMeData: {},
- shouldShowPaypal: true,
betas: [],
anchorRef: () => {},
};
@@ -73,15 +64,6 @@ function AddPaymentMethodMenu(props) {
},
]
: []),
- ...(props.shouldShowPaypal && !props.payPalMeData.description
- ? [
- {
- text: props.translate('common.payPalMe'),
- icon: Expensicons.PayPal,
- onSelected: () => props.onItemSelected(CONST.PAYMENT_METHODS.PAYPAL),
- },
- ]
- : []),
]}
withoutOverlay
/>
@@ -96,9 +78,6 @@ export default compose(
withWindowDimensions,
withLocalize,
withOnyx({
- payPalMeData: {
- key: ONYXKEYS.PAYPAL,
- },
betas: {
key: ONYXKEYS.BETAS,
},
diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js
index e2843ba7fae8..dbe7e46ff6aa 100644
--- a/src/components/AddPlaidBankAccount.js
+++ b/src/components/AddPlaidBankAccount.js
@@ -1,7 +1,6 @@
import _ from 'underscore';
-import React, {useEffect, useRef, useCallback, useMemo} from 'react';
+import React, {useEffect, useRef, useCallback} from 'react';
import {ActivityIndicator, View} from 'react-native';
-import {useIsFocused} from '@react-navigation/native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
@@ -39,9 +38,6 @@ const propTypes = {
/** Fired when the user exits the Plaid flow */
onExitPlaid: PropTypes.func,
- /** Fired when the screen is blurred */
- onBlurPlaid: PropTypes.func,
-
/** Fired when the user selects an account */
onSelect: PropTypes.func,
@@ -65,7 +61,6 @@ const defaultProps = {
selectedPlaidAccountID: '',
plaidLinkToken: '',
onExitPlaid: () => {},
- onBlurPlaid: () => {},
onSelect: () => {},
text: '',
receivedRedirectURI: null,
@@ -80,7 +75,6 @@ function AddPlaidBankAccount({
selectedPlaidAccountID,
plaidLinkToken,
onExitPlaid,
- onBlurPlaid,
onSelect,
text,
receivedRedirectURI,
@@ -94,7 +88,6 @@ function AddPlaidBankAccount({
const {translate} = useLocalize();
const {isOffline} = useNetwork();
- const isFocused = useIsFocused();
/**
* @returns {String}
@@ -109,11 +102,6 @@ function AddPlaidBankAccount({
}
};
- /**
- * @returns {Array}
- */
- const plaidBankAccounts = useMemo(() => lodashGet(plaidData, 'bankAccounts') || [], [plaidData]);
-
/**
* @returns {Boolean}
* I'm using useCallback so the useEffect which uses this function doesn't run on every render.
@@ -163,13 +151,6 @@ function AddPlaidBankAccount({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
- useEffect(() => {
- if (isFocused || plaidBankAccounts.length) {
- return;
- }
- onBlurPlaid();
- }, [isFocused, onBlurPlaid, plaidBankAccounts.length]);
-
useEffect(() => {
// If we are coming back from offline and we haven't authenticated with Plaid yet, we need to re-run our call to kick off Plaid
// previousNetworkState.current also makes sure that this doesn't run on the first render.
@@ -179,6 +160,7 @@ function AddPlaidBankAccount({
previousNetworkState.current = isOffline;
}, [allowDebit, bankAccountID, isAuthenticatedWithPlaid, isOffline]);
+ const plaidBankAccounts = lodashGet(plaidData, 'bankAccounts') || [];
const token = getPlaidLinkToken();
const options = _.map(plaidBankAccounts, (account) => ({
value: account.plaidAccountID,
diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js
index 1697dddba805..1b4200572664 100644
--- a/src/components/AddressSearch/index.js
+++ b/src/components/AddressSearch/index.js
@@ -34,7 +34,7 @@ const propTypes = {
onBlur: PropTypes.func,
/** Error text to display */
- errorText: PropTypes.string,
+ errorText: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object]))]),
/** Hint text to display */
hint: PropTypes.string,
@@ -300,7 +300,7 @@ function AddressSearch(props) {
query={query}
requestUrl={{
useOnPlatform: 'all',
- url: ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces&proxyUrl='}),
+ url: props.network.isOffline ? null : ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces&proxyUrl='}),
}}
textInputProps={{
InputComp: TextInput,
diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js
index bbb0662132d2..946b5e2ddec9 100755
--- a/src/components/AttachmentModal.js
+++ b/src/components/AttachmentModal.js
@@ -1,4 +1,4 @@
-import React, {useState, useCallback} from 'react';
+import React, {useState, useCallback, useRef} from 'react';
import PropTypes from 'prop-types';
import {View, Animated, Keyboard} from 'react-native';
import Str from 'expensify-common/lib/str';
@@ -25,6 +25,10 @@ import HeaderGap from './HeaderGap';
import SafeAreaConsumer from './SafeAreaConsumer';
import addEncryptedAuthTokenToURL from '../libs/addEncryptedAuthTokenToURL';
import reportPropTypes from '../pages/reportPropTypes';
+import * as Expensicons from './Icon/Expensicons';
+import useWindowDimensions from '../hooks/useWindowDimensions';
+import Navigation from '../libs/Navigation/Navigation';
+import ROUTES from '../ROUTES';
import useNativeDriver from '../libs/useNativeDriver';
/**
@@ -94,6 +98,7 @@ const defaultProps = {
};
function AttachmentModal(props) {
+ const onModalHideCallbackRef = useRef(null);
const [isModalOpen, setIsModalOpen] = useState(props.defaultOpen);
const [shouldLoadAttachment, setShouldLoadAttachment] = useState(false);
const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
@@ -106,6 +111,8 @@ function AttachmentModal(props) {
const [isConfirmButtonDisabled, setIsConfirmButtonDisabled] = useState(false);
const [confirmButtonFadeAnimation] = useState(new Animated.Value(1));
const [shouldShowDownloadButton, setShouldShowDownloadButton] = React.useState(true);
+ const {windowWidth} = useWindowDimensions();
+
const [file, setFile] = useState(
props.originalFileName
? {
@@ -331,6 +338,10 @@ function AttachmentModal(props) {
}}
onModalHide={(e) => {
props.onModalHide(e);
+ if (onModalHideCallbackRef.current) {
+ onModalHideCallbackRef.current();
+ }
+
setShouldLoadAttachment(false);
}}
propagateSwipe
@@ -339,12 +350,30 @@ function AttachmentModal(props) {
downloadAttachment(source)}
shouldShowCloseButton={!props.isSmallScreenWidth}
shouldShowBackButton={props.isSmallScreenWidth}
onBackButtonPress={closeModal}
onCloseButtonPress={closeModal}
+ shouldShowThreeDotsButton={isAttachmentReceipt}
+ threeDotsAnchorPosition={styles.threeDotsPopoverOffsetAttachmentModal(windowWidth)}
+ threeDotsMenuItems={[
+ {
+ icon: Expensicons.Camera,
+ text: props.translate('common.replace'),
+ onSelected: () => {
+ onModalHideCallbackRef.current = () => Navigation.navigate(ROUTES.getEditRequestRoute(props.report.reportID, CONST.EDIT_REQUEST_FIELD.RECEIPT));
+ closeModal();
+ },
+ },
+ {
+ icon: Expensicons.Download,
+ text: props.translate('common.download'),
+ onSelected: () => downloadAttachment(source),
+ },
+ ]}
+ shouldOverlay
/>
{!_.isEmpty(props.report) ? (
diff --git a/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
new file mode 100644
index 000000000000..2c698d5c8a61
--- /dev/null
+++ b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
@@ -0,0 +1,34 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {View, PixelRatio} from 'react-native';
+import useWindowDimensions from '../../../hooks/useWindowDimensions';
+import styles from '../../../styles/styles';
+
+const propTypes = {
+ /** Cell Container styles */
+ style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
+};
+
+const defaultProps = {
+ style: [],
+};
+
+function AttachmentCarouselCellRenderer(props) {
+ const {windowWidth, isSmallScreenWidth} = useWindowDimensions();
+ const modalStyles = styles.centeredModalStyles(isSmallScreenWidth, true);
+ const style = [props.style, styles.h100, {width: PixelRatio.roundToNearestPixel(windowWidth - (modalStyles.marginHorizontal + modalStyles.borderWidth) * 2)}];
+
+ return (
+
+ );
+}
+
+AttachmentCarouselCellRenderer.propTypes = propTypes;
+AttachmentCarouselCellRenderer.defaultProps = defaultProps;
+AttachmentCarouselCellRenderer.displayName = 'AttachmentCarouselCellRenderer';
+
+export default React.memo(AttachmentCarouselCellRenderer);
diff --git a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js
index b1a844e4172d..adee75cb4fa9 100644
--- a/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js
+++ b/src/components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage.js
@@ -41,8 +41,11 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI
// to prevent the image transformer from flashing while still rendering
// Instead, we show the fallback image while the image transformer is loading the image
useEffect(() => {
- if (initialIsActive) setTimeout(() => setIsActive(true), 1);
- else setIsActive(false);
+ if (initialIsActive) {
+ setTimeout(() => setIsActive(true), 1);
+ } else {
+ setIsActive(false);
+ }
}, [initialIsActive]);
const [initialActivePageLoad, setInitialActivePageLoad] = useState(isActive);
@@ -51,8 +54,11 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI
// We delay hiding the fallback image while image transformer is still rendering
useEffect(() => {
- if (isImageLoading) setShowFallback(true);
- else setTimeout(() => setShowFallback(false), 100);
+ if (isImageLoading) {
+ setShowFallback(true);
+ } else {
+ setTimeout(() => setShowFallback(false), 100);
+ }
}, [isImageLoading]);
return (
@@ -127,7 +133,9 @@ function AttachmentCarouselPage({source, isAuthTokenRequired, isActive: initialI
const scaledImageHeight = imageHeight * minImageScale;
// Don't update the dimensions if they are already set
- if (dimensions?.scaledImageWidth === scaledImageWidth && dimensions?.scaledImageHeight === scaledImageHeight) return;
+ if (dimensions?.scaledImageWidth === scaledImageWidth && dimensions?.scaledImageHeight === scaledImageHeight) {
+ return;
+ }
cachedDimensions.set(source, {
...dimensions,
diff --git a/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js b/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js
index 4475df168df2..b1c2864a05f6 100644
--- a/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js
+++ b/src/components/Attachments/AttachmentCarousel/Pager/ImageTransformer.js
@@ -306,7 +306,9 @@ function ImageTransformer({imageWidth, imageHeight, imageScaleX, imageScaleY, sc
stopAnimation();
})
.onFinalize((evt, success) => {
- if (!success || !onTap) return;
+ if (!success || !onTap) {
+ return;
+ }
runOnJS(onTap)();
});
@@ -432,7 +434,9 @@ function ImageTransformer({imageWidth, imageHeight, imageScaleX, imageScaleY, sc
const pinchGesture = Gesture.Pinch()
.onTouchesDown((evt, state) => {
// we don't want to activate pinch gesture when we are scrolling pager
- if (!isScrolling.value) return;
+ if (!isScrolling.value) {
+ return;
+ }
state.fail();
})
diff --git a/src/components/Attachments/AttachmentCarousel/index.js b/src/components/Attachments/AttachmentCarousel/index.js
index 574cb496d02f..00b603cdd7d9 100644
--- a/src/components/Attachments/AttachmentCarousel/index.js
+++ b/src/components/Attachments/AttachmentCarousel/index.js
@@ -3,6 +3,7 @@ import {View, FlatList, PixelRatio, Keyboard} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
import styles from '../../../styles/styles';
+import AttachmentCarouselCellRenderer from './AttachmentCarouselCellRenderer';
import CarouselActions from './CarouselActions';
import withWindowDimensions from '../../withWindowDimensions';
import CarouselButtons from './CarouselButtons';
@@ -12,7 +13,6 @@ import ONYXKEYS from '../../../ONYXKEYS';
import withLocalize from '../../withLocalize';
import compose from '../../../libs/compose';
import useCarouselArrows from './useCarouselArrows';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
import CarouselItem from './CarouselItem';
import Navigation from '../../../libs/Navigation/Navigation';
import BlockingView from '../../BlockingViews/BlockingView';
@@ -30,7 +30,6 @@ const viewabilityConfig = {
function AttachmentCarousel({report, reportActions, source, onNavigate, setDownloadButtonVisibility, translate}) {
const scrollRef = useRef(null);
- const {windowWidth, isSmallScreenWidth} = useWindowDimensions();
const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
const [containerWidth, setContainerWidth] = useState(0);
@@ -67,7 +66,9 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, setDownl
setDownloadButtonVisibility(initialPage !== -1);
// Update the parent modal's state with the source and name from the mapped attachments
- if (!_.isUndefined(attachmentsFromReport[initialPage])) onNavigate(attachmentsFromReport[initialPage]);
+ if (!_.isUndefined(attachmentsFromReport[initialPage])) {
+ onNavigate(attachmentsFromReport[initialPage]);
+ }
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [reportActions, compareImage]);
@@ -130,29 +131,6 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, setDownl
[containerWidth],
);
- /**
- * Defines how a container for a single attachment should be rendered
- * @param {Object} cellRendererProps
- * @returns {JSX.Element}
- */
- const renderCell = useCallback(
- (cellProps) => {
- // Use window width instead of layout width to address the issue in https://github.com/Expensify/App/issues/17760
- // considering horizontal margin and border width in centered modal
- const modalStyles = styles.centeredModalStyles(isSmallScreenWidth, true);
- const style = [cellProps.style, styles.h100, {width: PixelRatio.roundToNearestPixel(windowWidth - (modalStyles.marginHorizontal + modalStyles.borderWidth) * 2)}];
-
- return (
-
- );
- },
- [isSmallScreenWidth, windowWidth],
- );
-
/**
* Defines how a single attachment should be rendered
* @param {Object} item
@@ -224,7 +202,7 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, setDownl
windowSize={5}
maxToRenderPerBatch={3}
data={attachments}
- CellRendererComponent={renderCell}
+ CellRendererComponent={AttachmentCarouselCellRenderer}
renderItem={renderItem}
getItemLayout={getItemLayout}
keyExtractor={(item) => item.source}
diff --git a/src/components/Attachments/AttachmentCarousel/index.native.js b/src/components/Attachments/AttachmentCarousel/index.native.js
index a7a2f35a2ccc..bd12020341be 100644
--- a/src/components/Attachments/AttachmentCarousel/index.native.js
+++ b/src/components/Attachments/AttachmentCarousel/index.native.js
@@ -56,7 +56,9 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, onClose,
setDownloadButtonVisibility(initialPage !== -1);
// Update the parent modal's state with the source and name from the mapped attachments
- if (!_.isUndefined(attachmentsFromReport[initialPage])) onNavigate(attachmentsFromReport[initialPage]);
+ if (!_.isUndefined(attachmentsFromReport[initialPage])) {
+ onNavigate(attachmentsFromReport[initialPage]);
+ }
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [reportActions, compareImage]);
@@ -148,7 +150,9 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, onClose,
onPageSelected={({nativeEvent: {position: newPage}}) => updatePage(newPage)}
onPinchGestureChange={(newIsPinchGestureRunning) => {
setIsPinchGestureRunning(newIsPinchGestureRunning);
- if (!newIsPinchGestureRunning && !shouldShowArrows) setShouldShowArrows(true);
+ if (!newIsPinchGestureRunning && !shouldShowArrows) {
+ setShouldShowArrows(true);
+ }
}}
onSwipeDown={onClose}
containerWidth={containerDimensions.width}
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js
index 0767b2b68985..fdf151c4d5d0 100644
--- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js
@@ -25,7 +25,9 @@ function AttachmentViewPdf({file, encryptedSourceUrl, isFocused, isUsedInCarouse
attachmentCarouselPagerContext.onPinchGestureChange(!shouldPagerScroll);
- if (attachmentCarouselPagerContext.shouldPagerScroll.value === shouldPagerScroll) return;
+ if (attachmentCarouselPagerContext.shouldPagerScroll.value === shouldPagerScroll) {
+ return;
+ }
attachmentCarouselPagerContext.shouldPagerScroll.value = shouldPagerScroll;
}
diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js
index aa50d6db574b..4cc70f00d1ae 100644
--- a/src/components/AvatarWithImagePicker.js
+++ b/src/components/AvatarWithImagePicker.js
@@ -21,8 +21,11 @@ import stylePropTypes from '../styles/stylePropTypes';
import * as FileUtils from '../libs/fileDownload/FileUtils';
import getImageResolution from '../libs/fileDownload/getImageResolution';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
+import AttachmentModal from './AttachmentModal';
import DotIndicatorMessage from './DotIndicatorMessage';
import * as Browser from '../libs/Browser';
+import withNavigationFocus, {withNavigationFocusPropTypes} from './withNavigationFocus';
+import compose from '../libs/compose';
const propTypes = {
/** Avatar source to display */
@@ -79,7 +82,17 @@ const propTypes = {
// eslint-disable-next-line react/forbid-prop-types
errors: PropTypes.object,
+ /** Title for avatar preview modal */
+ headerTitle: PropTypes.string,
+
+ /** Avatar source for avatar preview modal */
+ previewSource: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
+
+ /** File name of the avatar */
+ originalFileName: PropTypes.string,
+
...withLocalizePropTypes,
+ ...withNavigationFocusPropTypes,
};
const defaultProps = {
@@ -98,6 +111,9 @@ const defaultProps = {
onErrorClose: () => {},
pendingAction: null,
errors: null,
+ headerTitle: '',
+ previewSource: '',
+ originalFileName: '',
};
class AvatarWithImagePicker extends React.Component {
@@ -129,6 +145,9 @@ class AvatarWithImagePicker extends React.Component {
}
componentDidUpdate(prevProps) {
+ if (!prevProps.isFocused && this.props.isFocused) {
+ this.setError(null, {});
+ }
if (!prevProps.isUploading && this.props.isUploading) {
this.animation.start();
} else if (prevProps.isUploading && !this.props.isUploading) {
@@ -273,58 +292,72 @@ class AvatarWithImagePicker extends React.Component {
-
- {({openPicker}) => {
- const menuItems = [
- {
- icon: Expensicons.Upload,
- text: this.props.translate('avatarWithImagePicker.uploadPhoto'),
- onSelected: () => {
- if (Browser.isSafari()) {
- return;
- }
- openPicker({
- onPicked: this.showAvatarCropModal,
+
+ {({show}) => (
+
+ {({openPicker}) => {
+ const menuItems = [
+ {
+ icon: Expensicons.Upload,
+ text: this.props.translate('avatarWithImagePicker.uploadPhoto'),
+ onSelected: () => {
+ if (Browser.isSafari()) {
+ return;
+ }
+ openPicker({
+ onPicked: this.showAvatarCropModal,
+ });
+ },
+ },
+ ];
+
+ // If current avatar isn't a default avatar, allow Remove Photo option
+ if (!this.props.isUsingDefaultAvatar) {
+ menuItems.push({
+ icon: Expensicons.Trashcan,
+ text: this.props.translate('avatarWithImagePicker.removePhoto'),
+ onSelected: () => {
+ this.setError(null, {});
+ this.props.onImageRemoved();
+ },
+ });
+
+ menuItems.push({
+ icon: Expensicons.Eye,
+ text: this.props.translate('avatarWithImagePicker.viewPhoto'),
+ onSelected: () => show(),
});
- },
- },
- ];
-
- // If current avatar isn't a default avatar, allow Remove Photo option
- if (!this.props.isUsingDefaultAvatar) {
- menuItems.push({
- icon: Expensicons.Trashcan,
- text: this.props.translate('avatarWithImagePicker.removePhoto'),
- onSelected: () => {
- this.setError(null, {});
- this.props.onImageRemoved();
- },
- });
- }
- return (
- this.setState({isMenuVisible: false})}
- onItemSelected={(item, index) => {
- this.setState({isMenuVisible: false});
- // In order for the file picker to open dynamically, the click
- // function must be called from within a event handler that was initiated
- // by the user on Safari.
- if (index === 0 && Browser.isSafari()) {
- openPicker({
- onPicked: this.showAvatarCropModal,
- });
- }
- }}
- menuItems={menuItems}
- anchorPosition={this.props.anchorPosition}
- withoutOverlay
- anchorRef={this.anchorRef}
- anchorAlignment={this.props.anchorAlignment}
- />
- );
- }}
-
+ }
+ return (
+ this.setState({isMenuVisible: false})}
+ onItemSelected={(item, index) => {
+ this.setState({isMenuVisible: false});
+ // In order for the file picker to open dynamically, the click
+ // function must be called from within a event handler that was initiated
+ // by the user on Safari.
+ if (index === 0 && Browser.isSafari()) {
+ openPicker({
+ onPicked: this.showAvatarCropModal,
+ });
+ }
+ }}
+ menuItems={menuItems}
+ anchorPosition={this.props.anchorPosition}
+ withoutOverlay
+ anchorRef={this.anchorRef}
+ anchorAlignment={this.props.anchorAlignment}
+ />
+ );
+ }}
+
+ )}
+
{this.state.validationError && (
Navigation.goBack(ROUTES.HOME),
shouldShowLink: true,
shouldShowBackButton: true,
onLinkPress: () => Navigation.dismissModal(),
diff --git a/src/components/ButtonWithDropdownMenu.js b/src/components/ButtonWithDropdownMenu.js
index 62eeb3030619..54d6c0deac5a 100644
--- a/src/components/ButtonWithDropdownMenu.js
+++ b/src/components/ButtonWithDropdownMenu.js
@@ -32,7 +32,7 @@ const propTypes = {
style: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
/** Menu options to display */
- /** e.g. [{text: 'Pay with Expensify', icon: Wallet}, {text: 'PayPal', icon: PayPal}] */
+ /** e.g. [{text: 'Pay with Expensify', icon: Wallet}] */
options: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.string.isRequired,
diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js
index 91c7e82e7887..9d4e0747cc18 100644
--- a/src/components/CategoryPicker/index.js
+++ b/src/components/CategoryPicker/index.js
@@ -46,7 +46,7 @@ function CategoryPicker({policyCategories, reportID, iouType, iou, policyRecentl
}, [policyCategories, selectedOptions, isCategoriesCountBelowThreshold]);
const sections = useMemo(
- () => OptionsListUtils.getNewChatOptions({}, {}, [], searchValue, selectedOptions, [], false, false, true, policyCategories, policyRecentlyUsedCategories, false).categoryOptions,
+ () => OptionsListUtils.getFilteredOptions({}, {}, [], searchValue, selectedOptions, [], false, false, true, policyCategories, policyRecentlyUsedCategories, false).categoryOptions,
[policyCategories, policyRecentlyUsedCategories, searchValue, selectedOptions],
);
diff --git a/src/components/Composer/index.android.js b/src/components/Composer/index.android.js
index d0805cbcc7c3..1132efa9e50e 100644
--- a/src/components/Composer/index.android.js
+++ b/src/components/Composer/index.android.js
@@ -97,7 +97,9 @@ function Composer({shouldClear, onClear, isDisabled, maxLines, forwardedRef, isC
* @return {Number}
*/
const maxNumberOfLines = useMemo(() => {
- if (isComposerFullSize) return 1000000;
+ if (isComposerFullSize) {
+ return 1000000;
+ }
return maxLines;
}, [isComposerFullSize, maxLines]);
diff --git a/src/components/Composer/index.ios.js b/src/components/Composer/index.ios.js
index c0a3859e6d01..0b2c93f6639e 100644
--- a/src/components/Composer/index.ios.js
+++ b/src/components/Composer/index.ios.js
@@ -97,7 +97,9 @@ function Composer({shouldClear, onClear, isDisabled, maxLines, forwardedRef, isC
* @return {Number}
*/
const maxNumberOfLines = useMemo(() => {
- if (isComposerFullSize) return undefined;
+ if (isComposerFullSize) {
+ return;
+ }
return maxLines;
}, [isComposerFullSize, maxLines]);
diff --git a/src/components/ConfirmedRoute.js b/src/components/ConfirmedRoute.js
index 4bcdc4738a3c..dab30e60ca55 100644
--- a/src/components/ConfirmedRoute.js
+++ b/src/components/ConfirmedRoute.js
@@ -1,9 +1,9 @@
import React, {useEffect} from 'react';
import PropTypes from 'prop-types';
-import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import lodashIsNil from 'lodash/isNil';
import _ from 'underscore';
import ONYXKEYS from '../ONYXKEYS';
import CONST from '../CONST';
@@ -13,9 +13,8 @@ import * as Expensicons from './Icon/Expensicons';
import theme from '../styles/themes/default';
import styles from '../styles/styles';
import transactionPropTypes from './transactionPropTypes';
-import BlockingView from './BlockingViews/BlockingView';
+import PendingMapView from './MapView/PendingMapView';
import useNetwork from '../hooks/useNetwork';
-import useLocalize from '../hooks/useLocalize';
import DistanceMapView from './DistanceMapView';
const propTypes = {
@@ -44,7 +43,7 @@ const getWaypointMarkers = (waypoints) => {
const lastWaypointIndex = numberOfWaypoints - 1;
return _.filter(
_.map(waypoints, (waypoint, key) => {
- if (!waypoint || waypoint.lng === undefined || waypoint.lat === undefined) {
+ if (!waypoint || lodashIsNil(waypoint.lat) || lodashIsNil(waypoint.lng)) {
return;
}
@@ -76,7 +75,6 @@ const getWaypointMarkers = (waypoints) => {
function ConfirmedRoute({mapboxAccessToken, transaction}) {
const {isOffline} = useNetwork();
- const {translate} = useLocalize();
const {route0: route} = transaction.routes || {};
const waypoints = lodashGet(transaction, 'comment.waypoints', {});
const coordinates = lodashGet(route, 'geometry.coordinates', []);
@@ -104,14 +102,7 @@ function ConfirmedRoute({mapboxAccessToken, transaction}) {
styleURL={CONST.MAPBOX.STYLE_URL}
/>
) : (
-
-
-
+
)}
>
);
diff --git a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js
index 6e6c46e971c0..cc305a628820 100644
--- a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js
+++ b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
+import _ from 'underscore';
import SkeletonViewContentLoader from 'react-content-loader/native';
import {Circle, Rect} from 'react-native-svg';
import {View} from 'react-native';
@@ -12,14 +13,26 @@ import styles from '../../styles/styles';
const propTypes = {
/** Whether to animate the skeleton view */
shouldAnimate: PropTypes.bool,
+
+ /** The size of the avatar */
+ avatarSize: PropTypes.oneOf(_.values(CONST.AVATAR_SIZE)),
+
+ /** Background color of the skeleton view */
+ backgroundColor: PropTypes.string,
+
+ /** Foreground color of the skeleton view */
+ foregroundColor: PropTypes.string,
};
const defaultProps = {
shouldAnimate: true,
+ avatarSize: CONST.AVATAR_SIZE.LARGE,
+ backgroundColor: themeColors.highlightBG,
+ foregroundColor: themeColors.border,
};
function CurrentUserPersonalDetailsSkeletonView(props) {
- const avatarPlaceholderSize = StyleUtils.getAvatarSize(CONST.AVATAR_SIZE.LARGE);
+ const avatarPlaceholderSize = StyleUtils.getAvatarSize(props.avatarSize);
const avatarPlaceholderRadius = avatarPlaceholderSize / 2;
const spaceBetweenAvatarAndHeadline = styles.mb3.marginBottom + styles.mt1.marginTop + (variables.lineHeightXXLarge - variables.fontSizeXLarge) / 2;
const headlineSize = variables.fontSizeXLarge;
@@ -29,8 +42,8 @@ function CurrentUserPersonalDetailsSkeletonView(props) {
1;
+ const isRouteAbsentWithoutErrors = !hasRoute && !hasRouteError;
+ const shouldFetchRoute = (isRouteAbsentWithoutErrors || haveValidatedWaypointsChanged) && !isLoadingRoute && _.size(validatedWaypoints) > 1;
const waypointMarkers = useMemo(
() =>
_.filter(
_.map(waypoints, (waypoint, key) => {
- if (!waypoint || !lodashHas(waypoint, 'lat') || !lodashHas(waypoint, 'lng') || lodashIsNull(waypoint.lat) || lodashIsNull(waypoint.lng)) {
+ if (!waypoint || lodashIsNil(waypoint.lat) || lodashIsNil(waypoint.lng)) {
return;
}
@@ -189,7 +189,7 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken,
useEffect(updateGradientVisibility, [scrollContainerHeight, scrollContentHeight]);
const navigateBack = () => {
- Navigation.goBack(isEditing ? ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID) : null);
+ Navigation.goBack(isEditing ? ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID) : ROUTES.HOME);
};
const navigateToNextPage = () => {
@@ -261,7 +261,10 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken,
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js
index d3268ebc54b0..27fd199a3895 100755
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js
@@ -104,7 +104,9 @@ class EmojiPickerMenu extends Component {
}
componentDidUpdate(prevProps) {
- if (prevProps.frequentlyUsedEmojis === this.props.frequentlyUsedEmojis) return;
+ if (prevProps.frequentlyUsedEmojis === this.props.frequentlyUsedEmojis) {
+ return;
+ }
const {filteredEmojis, headerEmojis, headerRowIndices} = this.getEmojisAndHeaderRowIndices();
this.emojis = filteredEmojis;
diff --git a/src/components/ErrorBoundary/BaseErrorBoundary.js b/src/components/ErrorBoundary/BaseErrorBoundary.js
index e479b04f7ade..d626442e81dd 100644
--- a/src/components/ErrorBoundary/BaseErrorBoundary.js
+++ b/src/components/ErrorBoundary/BaseErrorBoundary.js
@@ -1,5 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
+import {ErrorBoundary} from 'react-error-boundary';
import BootSplash from '../../libs/BootSplash';
import GenericErrorPage from '../../pages/ErrorPage/GenericErrorPage';
@@ -22,40 +23,27 @@ const defaultProps = {
* This component captures an error in the child component tree and logs it to the server
* It can be used to wrap the entire app as well as to wrap specific parts for more granularity
* @see {@link https://reactjs.org/docs/error-boundaries.html#where-to-place-error-boundaries}
+ * @return {React.Component}
*/
-class BaseErrorBoundary extends React.Component {
- constructor(props) {
- super(props);
- this.state = {hasError: false};
- this.clearError = this.clearError.bind(this);
- }
-
- static getDerivedStateFromError() {
- // Update state so the next render will show the fallback UI.
- return {hasError: true};
- }
-
- componentDidCatch(error, errorInfo) {
- this.props.logError(this.props.errorMessage, error, JSON.stringify(errorInfo));
-
+function BaseErrorBoundary({logError, errorMessage, children}) {
+ const catchError = (error, errorInfo) => {
+ logError(errorMessage, error, JSON.stringify(errorInfo));
// We hide the splash screen since the error might happened during app init
BootSplash.hide();
- }
-
- clearError() {
- this.setState({hasError: false});
- }
-
- render() {
- if (this.state.hasError) {
- return ;
- }
-
- return this.props.children;
- }
+ };
+
+ return (
+ }
+ onError={catchError}
+ >
+ {children}
+
+ );
}
BaseErrorBoundary.propTypes = propTypes;
BaseErrorBoundary.defaultProps = defaultProps;
+BaseErrorBoundary.displayName = 'BaseErrorBoundary';
export default BaseErrorBoundary;
diff --git a/src/components/ExceededCommentLength.js b/src/components/ExceededCommentLength.js
index 2aa50779e10f..7c9ec4d2db25 100644
--- a/src/components/ExceededCommentLength.js
+++ b/src/components/ExceededCommentLength.js
@@ -4,6 +4,7 @@ import {debounce} from 'lodash';
import {withOnyx} from 'react-native-onyx';
import CONST from '../CONST';
import * as ReportUtils from '../libs/ReportUtils';
+import useLocalize from '../hooks/useLocalize';
import Text from './Text';
import styles from '../styles/styles';
import ONYXKEYS from '../ONYXKEYS';
@@ -25,6 +26,7 @@ const defaultProps = {
};
function ExceededCommentLength(props) {
+ const {numberFormat, translate} = useLocalize();
const [commentLength, setCommentLength] = useState(0);
const updateCommentLength = useMemo(
() =>
@@ -44,7 +46,14 @@ function ExceededCommentLength(props) {
return null;
}
- return {`${commentLength}/${CONST.MAX_COMMENT_LENGTH}`};
+ return (
+
+ {translate('composer.commentExceededMaxLength', {formattedMaxLength: numberFormat(CONST.MAX_COMMENT_LENGTH)})}
+
+ );
}
ExceededCommentLength.propTypes = propTypes;
diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
index 5417f7af6820..4b61d55ae228 100755
--- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
+++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
@@ -6,6 +6,7 @@ import htmlRenderers from './HTMLRenderers';
import * as HTMLEngineUtils from './htmlEngineUtils';
import styles from '../../styles/styles';
import fontFamily from '../../styles/fontFamily';
+import convertToLTR from '../../libs/convertToLTR';
const propTypes = {
/** Whether text elements should be selectable */
@@ -71,6 +72,10 @@ function BaseHTMLEngineProvider(props) {
enableCSSInlineProcessing={false}
systemFonts={_.values(fontFamily)}
fallbackFonts={fallbackFonts}
+ domVisitors={{
+ // eslint-disable-next-line no-param-reassign
+ onText: (text) => (text.data = convertToLTR(text.data)),
+ }}
>
- {/* Native devices do not support margin between nested text */}
+
{' '}
- {props.translate('reportActionCompose.edited')}
+
+ {props.translate('reportActionCompose.edited')}
+
);
}
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
index 7f7753dfea44..947a15ac6efb 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
@@ -11,6 +11,7 @@ import personalDetailsPropType from '../../../pages/personalDetailsPropType';
import * as StyleUtils from '../../../styles/StyleUtils';
import * as PersonalDetailsUtils from '../../../libs/PersonalDetailsUtils';
import TextLink from '../../TextLink';
+import CONST from '../../../CONST';
const propTypes = {
...htmlRendererPropTypes,
@@ -31,8 +32,8 @@ const showUserDetails = (email) => Navigation.navigate(ROUTES.getDetailsRoute(em
function MentionUserRenderer(props) {
const defaultRendererProps = _.omit(props, ['TDefaultRenderer', 'style']);
- // We need to remove the leading @ from data as it is not part of the login
- const loginWithoutLeadingAt = props.tnode.data ? props.tnode.data.slice(1) : '';
+ // We need to remove the LTR unicode and leading @ from data as it is not part of the login
+ const loginWithoutLeadingAt = props.tnode.data ? props.tnode.data.replace(CONST.UNICODE.LTR, '').slice(1) : '';
const accountID = _.first(PersonalDetailsUtils.getAccountIDsByLogins([loginWithoutLeadingAt]));
diff --git a/src/components/HTMLEngineProvider/applyStrikethrough/index.js b/src/components/HTMLEngineProvider/applyStrikethrough/index.js
deleted file mode 100644
index b754a37dbde9..000000000000
--- a/src/components/HTMLEngineProvider/applyStrikethrough/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-function applyStrikethrough(html) {
- return html;
-}
-
-export default applyStrikethrough;
diff --git a/src/components/HTMLEngineProvider/applyStrikethrough/index.native.js b/src/components/HTMLEngineProvider/applyStrikethrough/index.native.js
deleted file mode 100644
index 266e4eb20f62..000000000000
--- a/src/components/HTMLEngineProvider/applyStrikethrough/index.native.js
+++ /dev/null
@@ -1,8 +0,0 @@
-function applyStrikethrough(html, isPendingDelete) {
- if (isPendingDelete) {
- return `${html}`;
- }
- return html;
-}
-
-export default applyStrikethrough;
diff --git a/src/components/StaticHeaderPageLayout.js b/src/components/HeaderPageLayout.js
similarity index 53%
rename from src/components/StaticHeaderPageLayout.js
rename to src/components/HeaderPageLayout.js
index f97e42329942..bec1e52b1cad 100644
--- a/src/components/StaticHeaderPageLayout.js
+++ b/src/components/HeaderPageLayout.js
@@ -10,6 +10,8 @@ import themeColors from '../styles/themes/default';
import * as StyleUtils from '../styles/StyleUtils';
import useWindowDimensions from '../hooks/useWindowDimensions';
import FixedFooter from './FixedFooter';
+import useNetwork from '../hooks/useNetwork';
+import * as Browser from '../libs/Browser';
const propTypes = {
...headerWithBackButtonPropTypes,
@@ -22,16 +24,26 @@ const propTypes = {
/** A fixed footer to display at the bottom of the page. */
footer: PropTypes.node,
+
+ /** The image to display in the upper half of the screen. */
+ header: PropTypes.node,
+
+ /** Style to apply to the header image container */
+ // eslint-disable-next-line react/forbid-prop-types
+ headerContainerStyles: PropTypes.arrayOf(PropTypes.object),
};
const defaultProps = {
backgroundColor: themeColors.appBG,
+ header: null,
+ headerContainerStyles: [],
footer: null,
};
-function StaticHeaderPageLayout({backgroundColor, children, image: Image, footer, imageContainerStyle, style, ...propsToPassToHeader}) {
- const {windowHeight} = useWindowDimensions();
-
+function HeaderPageLayout({backgroundColor, children, footer, headerContainerStyles, style, headerContent, ...propsToPassToHeader}) {
+ const {windowHeight, isSmallScreenWidth} = useWindowDimensions();
+ const {isOffline} = useNetwork();
+ const appBGColor = StyleUtils.getBackgroundColorStyle(themeColors.appBG);
const {titleColor, iconFill} = useMemo(() => {
const isColorfulBackground = backgroundColor !== themeColors.appBG;
return {
@@ -45,7 +57,7 @@ function StaticHeaderPageLayout({backgroundColor, children, image: Image, footer
style={[StyleUtils.getBackgroundColorStyle(backgroundColor)]}
shouldEnablePickerAvoiding={false}
includeSafeAreaPaddingBottom={false}
- offlineIndicatorStyle={[StyleUtils.getBackgroundColorStyle(themeColors.appBG)]}
+ offlineIndicatorStyle={[appBGColor]}
>
{({safeAreaPaddingBottomStyle}) => (
<>
@@ -55,27 +67,24 @@ function StaticHeaderPageLayout({backgroundColor, children, image: Image, footer
titleColor={titleColor}
iconFill={iconFill}
/>
-
+
+ {/** Safari on ios/mac has a bug where overscrolling the page scrollview shows green background color. This is a workaround to fix that. https://github.com/Expensify/App/issues/23422 */}
+ {Browser.isSafari() && (
+
+
+
+
+ )}
-
-
-
+ {!Browser.isSafari() && }
+
+ {headerContent}
- {children}
+ {children}
{!_.isNull(footer) && {footer}}
@@ -85,8 +94,8 @@ function StaticHeaderPageLayout({backgroundColor, children, image: Image, footer
);
}
-StaticHeaderPageLayout.propTypes = propTypes;
-StaticHeaderPageLayout.defaultProps = defaultProps;
-StaticHeaderPageLayout.displayName = 'StaticHeaderPageLayout';
+HeaderPageLayout.propTypes = propTypes;
+HeaderPageLayout.defaultProps = defaultProps;
+HeaderPageLayout.displayName = 'HeaderPageLayout';
-export default StaticHeaderPageLayout;
+export default HeaderPageLayout;
diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js
index bbf905cc1ac2..aab54612e206 100755
--- a/src/components/HeaderWithBackButton/index.js
+++ b/src/components/HeaderWithBackButton/index.js
@@ -22,7 +22,7 @@ import useKeyboardState from '../../hooks/useKeyboardState';
function HeaderWithBackButton({
iconFill = undefined,
guidesCallTaskID = '',
- onBackButtonPress = () => Navigation.goBack(),
+ onBackButtonPress = () => Navigation.goBack(ROUTES.HOME),
onCloseButtonPress = () => Navigation.dismissModal(),
onDownloadButtonPress = () => {},
onThreeDotsButtonPress = () => {},
@@ -47,6 +47,7 @@ function HeaderWithBackButton({
},
threeDotsMenuItems = [],
children = null,
+ shouldOverlay = false,
}) {
const [isDownloadButtonActive, temporarilyDisableDownloadButton] = useThrottledButtonState();
const {translate} = useLocalize();
@@ -137,6 +138,7 @@ function HeaderWithBackButton({
menuItems={threeDotsMenuItems}
onIconPress={onThreeDotsButtonPress}
anchorPosition={threeDotsAnchorPosition}
+ shouldOverlay={shouldOverlay}
/>
)}
{shouldShowCloseButton && (
diff --git a/src/components/Hoverable/hoverablePropTypes.js b/src/components/Hoverable/hoverablePropTypes.js
index 9fb2e3bc7306..d483a06d6aaf 100644
--- a/src/components/Hoverable/hoverablePropTypes.js
+++ b/src/components/Hoverable/hoverablePropTypes.js
@@ -12,12 +12,16 @@ const propTypes = {
/** Function that executes when the mouse leaves the children. */
onHoverOut: PropTypes.func,
+
+ /** Decides whether to handle the scroll behaviour to show hover once the scroll ends */
+ shouldHandleScroll: PropTypes.bool,
};
const defaultProps = {
disabled: false,
onHoverIn: () => {},
onHoverOut: () => {},
+ shouldHandleScroll: false,
};
export {propTypes, defaultProps};
diff --git a/src/components/Hoverable/index.js b/src/components/Hoverable/index.js
index 0b560703a069..7dd918f15cf4 100644
--- a/src/components/Hoverable/index.js
+++ b/src/components/Hoverable/index.js
@@ -1,7 +1,9 @@
import _ from 'underscore';
import React, {Component} from 'react';
+import {DeviceEventEmitter} from 'react-native';
import {propTypes, defaultProps} from './hoverablePropTypes';
import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
+import CONST from '../../CONST';
/**
* It is necessary to create a Hoverable component instead of relying solely on Pressable support for hover state,
@@ -19,12 +21,37 @@ class Hoverable extends Component {
isHovered: false,
};
+ this.isHoveredRef = false;
+ this.isScrollingRef = false;
this.wrapperView = null;
}
componentDidMount() {
document.addEventListener('visibilitychange', this.handleVisibilityChange);
document.addEventListener('mouseover', this.checkHover);
+
+ /**
+ * Only add the scrolling listener if the shouldHandleScroll prop is true
+ * and the scrollingListener is not already set.
+ */
+ if (!this.scrollingListener && this.props.shouldHandleScroll) {
+ this.scrollingListener = DeviceEventEmitter.addListener(CONST.EVENTS.SCROLLING, (scrolling) => {
+ /**
+ * If user has stopped scrolling and the isHoveredRef is true, then we should update the hover state.
+ */
+ if (!scrolling && this.isHoveredRef) {
+ this.setState({isHovered: this.isHoveredRef}, this.props.onHoverIn);
+ } else if (scrolling && this.isHoveredRef) {
+ /**
+ * If the user has started scrolling and the isHoveredRef is true, then we should set the hover state to false.
+ * This is to hide the existing hover and reaction bar.
+ */
+ this.isHoveredRef = false;
+ this.setState({isHovered: false}, this.props.onHoverOut);
+ }
+ this.isScrollingRef = scrolling;
+ });
+ }
}
componentDidUpdate(prevProps) {
@@ -40,6 +67,9 @@ class Hoverable extends Component {
componentWillUnmount() {
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
document.removeEventListener('mouseover', this.checkHover);
+ if (this.scrollingListener) {
+ this.scrollingListener.remove();
+ }
}
/**
@@ -52,6 +82,19 @@ class Hoverable extends Component {
return;
}
+ /**
+ * Capture whther or not the user is hovering over the component.
+ * We will use this to determine if we should update the hover state when the user has stopped scrolling.
+ */
+ this.isHoveredRef = isHovered;
+
+ /**
+ * If the isScrollingRef is true, then the user is scrolling and we should not update the hover state.
+ */
+ if (this.isScrollingRef && this.props.shouldHandleScroll && !this.state.isHovered) {
+ return;
+ }
+
if (isHovered !== this.state.isHovered) {
this.setState({isHovered}, isHovered ? this.props.onHoverIn : this.props.onHoverOut);
}
diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js
index 42db57068edc..a0c8b72d755a 100644
--- a/src/components/Icon/Expensicons.js
+++ b/src/components/Icon/Expensicons.js
@@ -82,7 +82,6 @@ import NewWorkspace from '../../../assets/images/new-workspace.svg';
import Offline from '../../../assets/images/offline.svg';
import OfflineCloud from '../../../assets/images/offline-cloud.svg';
import Paperclip from '../../../assets/images/paperclip.svg';
-import PayPal from '../../../assets/images/paypal.svg';
import Paycheck from '../../../assets/images/paycheck.svg';
import Pencil from '../../../assets/images/pencil.svg';
import Phone from '../../../assets/images/phone.svg';
@@ -216,7 +215,6 @@ export {
Offline,
OfflineCloud,
Paperclip,
- PayPal,
Paycheck,
Pencil,
Phone,
diff --git a/src/components/IllustratedHeaderPageLayout.js b/src/components/IllustratedHeaderPageLayout.js
index 92a9c8b8552b..ac916117094b 100644
--- a/src/components/IllustratedHeaderPageLayout.js
+++ b/src/components/IllustratedHeaderPageLayout.js
@@ -1,18 +1,10 @@
-import _ from 'underscore';
import React from 'react';
import PropTypes from 'prop-types';
-import {ScrollView, View} from 'react-native';
import Lottie from 'lottie-react-native';
import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
-import HeaderWithBackButton from './HeaderWithBackButton';
-import ScreenWrapper from './ScreenWrapper';
import styles from '../styles/styles';
import themeColors from '../styles/themes/default';
-import * as StyleUtils from '../styles/StyleUtils';
-import useWindowDimensions from '../hooks/useWindowDimensions';
-import FixedFooter from './FixedFooter';
-import useNetwork from '../hooks/useNetwork';
-import * as Browser from '../libs/Browser';
+import HeaderPageLayout from './HeaderPageLayout';
const propTypes = {
...headerWithBackButtonPropTypes,
@@ -40,54 +32,28 @@ const defaultProps = {
};
function IllustratedHeaderPageLayout({backgroundColor, children, illustration, footer, overlayContent, ...propsToPassToHeader}) {
- const {isOffline} = useNetwork();
- const {isSmallScreenWidth, windowHeight} = useWindowDimensions();
- const appBGColor = StyleUtils.getBackgroundColorStyle(themeColors.appBG);
-
return (
-
- {({safeAreaPaddingBottomStyle}) => (
+
-
-
- {/* Safari on ios/mac has a bug where overscrolling the page scrollview shows green the background color. This is a workaround to fix that. https://github.com/Expensify/App/issues/23422 */}
- {Browser.isSafari() && (
-
-
-
-
- )}
-
- {!Browser.isSafari() && }
-
-
- {overlayContent && overlayContent()}
-
- {children}
-
- {!_.isNull(footer) && {footer}}
-
+ {overlayContent && overlayContent()}
>
- )}
-
+ }
+ headerContainerStyles={[styles.justifyContentCenter, styles.w100]}
+ footer={footer}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...propsToPassToHeader}
+ >
+ {children}
+
);
}
diff --git a/src/components/ImageView/index.js b/src/components/ImageView/index.js
index c92bd7738253..e0dce180043b 100644
--- a/src/components/ImageView/index.js
+++ b/src/components/ImageView/index.js
@@ -87,7 +87,9 @@ function ImageView({isAuthTokenRequired, url, fileName}) {
};
const imageLoadingStart = () => {
- if (!isLoading) return;
+ if (!isLoading) {
+ return;
+ }
setIsLoading(true);
setZoomScale(0);
setIsZoomed(false);
@@ -141,11 +143,16 @@ function ImageView({isAuthTokenRequired, url, fileName}) {
*/
const onContainerPress = (e) => {
if (!isZoomed && !isDragging) {
- const {offsetX, offsetY} = e.nativeEvent;
- // Dividing clicked positions by the zoom scale to get coordinates
- // so that once we zoom we will scroll to the clicked location.
- const delta = getScrollOffset(offsetX / zoomScale, offsetY / zoomScale);
- setZoomDelta(delta);
+ if (e.nativeEvent) {
+ const {offsetX, offsetY} = e.nativeEvent;
+
+ // Dividing clicked positions by the zoom scale to get coordinates
+ // so that once we zoom we will scroll to the clicked location.
+ const delta = getScrollOffset(offsetX / zoomScale, offsetY / zoomScale);
+ setZoomDelta(delta);
+ } else {
+ setZoomDelta({offsetX: 0, offsetY: 0});
+ }
}
if (isZoomed && isDragging && isMouseDown) {
@@ -225,14 +232,14 @@ function ImageView({isAuthTokenRequired, url, fileName}) {
source={{uri: url}}
isAuthTokenRequired={isAuthTokenRequired}
// Hide image until finished loading to prevent showing preview with wrong dimensions.
- style={isLoading ? undefined : [styles.w100, styles.h100]}
+ style={isLoading || zoomScale === 0 ? undefined : [styles.w100, styles.h100]}
// When Image dimensions are lower than the container boundary(zoomscale <= 1), use `contain` to render the image with natural dimensions.
// Both `center` and `contain` keeps the image centered on both x and y axis.
resizeMode={zoomScale > 1 ? Image.resizeMode.center : Image.resizeMode.contain}
onLoadStart={imageLoadingStart}
onLoad={imageLoad}
/>
- {isLoading && }
+ {(isLoading || zoomScale === 0) && }
);
}
diff --git a/src/components/InvertedFlatList/index.js b/src/components/InvertedFlatList/index.js
index 923a17210af7..74409e9a0fe0 100644
--- a/src/components/InvertedFlatList/index.js
+++ b/src/components/InvertedFlatList/index.js
@@ -1,9 +1,10 @@
-import React, {forwardRef} from 'react';
+import React, {forwardRef, useEffect, useRef} from 'react';
import PropTypes from 'prop-types';
-import {FlatList, StyleSheet} from 'react-native';
+import {DeviceEventEmitter, FlatList, StyleSheet} from 'react-native';
import _ from 'underscore';
import BaseInvertedFlatList from './BaseInvertedFlatList';
import styles from '../../styles/styles';
+import CONST from '../../CONST';
const propTypes = {
/** Passed via forwardRef so we can access the FlatList ref */
@@ -14,43 +15,118 @@ const propTypes = {
/** Any additional styles to apply */
// eslint-disable-next-line react/forbid-prop-types
contentContainerStyle: PropTypes.any,
+
+ /** Same as for FlatList */
+ onScroll: PropTypes.func,
};
// This is adapted from https://codesandbox.io/s/react-native-dsyse
// It's a HACK alert since FlatList has inverted scrolling on web
-class InvertedFlatList extends React.Component {
- constructor(props) {
- super(props);
+function InvertedFlatList(props) {
+ const {innerRef, contentContainerStyle} = props;
+ const listRef = React.createRef();
- this.list = undefined;
- }
+ const lastScrollEvent = useRef(null);
+ const scrollEndTimeout = useRef(null);
+ const updateInProgress = useRef(false);
+ const eventHandler = useRef(null);
- componentDidMount() {
- if (!_.isFunction(this.props.innerRef)) {
+ useEffect(() => {
+ if (!_.isFunction(innerRef)) {
// eslint-disable-next-line no-param-reassign
- this.props.innerRef.current = this.list;
+ innerRef.current = listRef.current;
} else {
- this.props.innerRef(this.list);
+ innerRef(listRef);
+ }
+
+ return () => {
+ if (scrollEndTimeout.current) {
+ clearTimeout(scrollEndTimeout.current);
+ }
+
+ if (eventHandler.current) {
+ eventHandler.current.remove();
+ }
+ };
+ }, [innerRef, listRef]);
+
+ /**
+ * Emits when the scrolling is in progress. Also,
+ * invokes the onScroll callback function from props.
+ *
+ * @param {Event} event - The onScroll event from the FlatList
+ */
+ const onScroll = (event) => {
+ props.onScroll(event);
+
+ if (!updateInProgress.current) {
+ updateInProgress.current = true;
+ eventHandler.current = DeviceEventEmitter.emit(CONST.EVENTS.SCROLLING, true);
+ }
+ };
+
+ /**
+ * Emits when the scrolling has ended.
+ */
+ const onScrollEnd = () => {
+ eventHandler.current = DeviceEventEmitter.emit(CONST.EVENTS.SCROLLING, false);
+ updateInProgress.current = false;
+ };
+
+ /**
+ * Decides whether the scrolling has ended or not. If it has ended,
+ * then it calls the onScrollEnd function. Otherwise, it calls the
+ * onScroll function and pass the event to it.
+ *
+ * This is a temporary work around, since react-native-web doesn't
+ * support onScrollBeginDrag and onScrollEndDrag props for FlatList.
+ * More info:
+ * https://github.com/necolas/react-native-web/pull/1305
+ *
+ * This workaround is taken from below and refactored to fit our needs:
+ * https://github.com/necolas/react-native-web/issues/1021#issuecomment-984151185
+ *
+ * @param {Event} event - The onScroll event from the FlatList
+ */
+ const handleScroll = (event) => {
+ onScroll(event);
+ const timestamp = Date.now();
+
+ if (scrollEndTimeout.current) {
+ clearTimeout(scrollEndTimeout.current);
}
- }
-
- render() {
- return (
- (this.list = el)}
- shouldMeasureItems
- contentContainerStyle={StyleSheet.compose(this.props.contentContainerStyle, styles.justifyContentEnd)}
- />
- );
- }
+
+ if (lastScrollEvent.current) {
+ scrollEndTimeout.current = setTimeout(() => {
+ if (lastScrollEvent.current !== timestamp) {
+ return;
+ }
+ // Scroll has ended
+ lastScrollEvent.current = null;
+ onScrollEnd();
+ }, 250);
+ }
+
+ lastScrollEvent.current = timestamp;
+ };
+
+ return (
+
+ );
}
InvertedFlatList.propTypes = propTypes;
InvertedFlatList.defaultProps = {
contentContainerStyle: {},
+ onScroll: () => {},
};
export default forwardRef((props, ref) => (
diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js
index 4684901e47b1..ebf115c5de59 100644
--- a/src/components/KYCWall/BaseKYCWall.js
+++ b/src/components/KYCWall/BaseKYCWall.js
@@ -142,7 +142,6 @@ class KYCWall extends React.Component {
vertical: this.state.anchorPositionVertical,
horizontal: this.state.anchorPositionHorizontal,
}}
- shouldShowPaypal={false}
onItemSelected={(item) => {
this.setState({shouldShowAddPaymentMenu: false});
if (item === CONST.PAYMENT_METHODS.BANK_ACCOUNT) {
diff --git a/src/components/MapView/MapView.web.tsx b/src/components/MapView/MapView.web.tsx
index d1b26df8b00e..ce13cee10f54 100644
--- a/src/components/MapView/MapView.web.tsx
+++ b/src/components/MapView/MapView.web.tsx
@@ -44,6 +44,21 @@ const MapView = forwardRef(
map.fitBounds([northEast, southWest], {padding: mapPadding});
}, [waypoints, mapRef, mapPadding]);
+ useEffect(() => {
+ if (!mapRef) {
+ return;
+ }
+
+ const resizeObserver = new ResizeObserver(() => {
+ mapRef.resize();
+ });
+ resizeObserver.observe(mapRef.getContainer());
+
+ return () => {
+ resizeObserver?.disconnect();
+ };
+ }, [mapRef]);
+
useImperativeHandle(
ref,
() => ({
diff --git a/src/components/MapView/MapViewTypes.ts b/src/components/MapView/MapViewTypes.ts
index de32528d077e..dc56cb4642c4 100644
--- a/src/components/MapView/MapViewTypes.ts
+++ b/src/components/MapView/MapViewTypes.ts
@@ -27,6 +27,14 @@ type DirectionProps = {
coordinates: Array<[number, number]>;
};
+type PendingMapViewProps = {
+ /** Title message below the icon */
+ title?: string;
+
+ /** Subtitle message below the title */
+ subtitle?: string;
+};
+
// Initial state of the map
type InitialState = {
// Coordinate on which to center the map
@@ -55,4 +63,4 @@ type MapViewHandle = {
fitBounds: (ne: [number, number], sw: [number, number], paddingConfig?: number | number[], animationDuration?: number) => void;
};
-export type {DirectionStyle, WayPoint, MapViewProps, DirectionProps, MapViewHandle};
+export type {DirectionStyle, WayPoint, MapViewProps, DirectionProps, PendingMapViewProps, MapViewHandle};
diff --git a/src/components/MapView/PendingMapView.tsx b/src/components/MapView/PendingMapView.tsx
new file mode 100644
index 000000000000..6a35d2a9c369
--- /dev/null
+++ b/src/components/MapView/PendingMapView.tsx
@@ -0,0 +1,36 @@
+import React from 'react';
+import {View} from 'react-native';
+import _ from 'lodash';
+import variables from '../../styles/variables';
+import styles from '../../styles/styles';
+import Icon from '../Icon';
+import {PendingMapViewProps} from './MapViewTypes';
+import BlockingView from '../BlockingViews/BlockingView';
+import * as Expensicons from '../Icon/Expensicons';
+
+function PendingMapView({title = '', subtitle = ''}: PendingMapViewProps) {
+ const hasTextContent = !_.isEmpty(title) || !_.isEmpty(subtitle);
+
+ return (
+
+ {hasTextContent ? (
+
+ ) : (
+
+
+
+ )}
+
+ );
+}
+
+export default PendingMapView;
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index c8906889612f..bb4eeb7a18ac 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -1,5 +1,5 @@
import _ from 'underscore';
-import React, {useEffect} from 'react';
+import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import Text from './Text';
@@ -25,6 +25,10 @@ import * as Session from '../libs/actions/Session';
import Hoverable from './Hoverable';
import useWindowDimensions from '../hooks/useWindowDimensions';
import RenderHTML from './RenderHTML';
+import getPlatform from '../libs/getPlatform';
+
+const platform = getPlatform();
+const isNative = platform === CONST.PLATFORM.IOS || platform === CONST.PLATFORM.ANDROID;
const propTypes = menuItemPropTypes;
@@ -119,6 +123,18 @@ const MenuItem = React.forwardRef((props, ref) => {
titleRef.current = props.title;
}, [props.title, props.shouldParseTitle]);
+ const getProcessedTitle = useMemo(() => {
+ if (props.shouldRenderAsHTML) {
+ return convertToLTR(props.title);
+ }
+
+ if (props.shouldParseTitle) {
+ return html;
+ }
+
+ return '';
+ }, [props.title, props.shouldRenderAsHTML, props.shouldParseTitle, html]);
+
return (
{(isHovered) => (
@@ -235,10 +251,15 @@ const MenuItem = React.forwardRef((props, ref) => {
)}
- {Boolean(props.title) && Boolean(props.shouldRenderAsHTML) && }
-
- {Boolean(props.shouldParseTitle) && Boolean(html.length) && !props.shouldRenderAsHTML && ${html}`} />}
-
+ {Boolean(props.title) &&
+ (Boolean(props.shouldRenderAsHTML) || (Boolean(props.shouldParseTitle) && Boolean(html.length))) &&
+ (isNative ? (
+
+ ) : (
+
+
+
+ ))}
{!props.shouldRenderAsHTML && !html.length && Boolean(props.title) && (
{
{convertToLTR(props.title)}
)}
-
{Boolean(props.shouldShowTitleIcon) && (
{
- Modal.willAlertModalBecomeVisible(isVisible);
-
- // To handle closing any modal already visible when this modal is mounted, i.e. PopoverReportActionContextMenu
- Modal.setCloseModal(isVisible ? onClose : null);
- }, [isVisible, onClose]);
+ isVisibleRef.current = isVisible;
+ if (isVisible) {
+ Modal.willAlertModalBecomeVisible(true);
+ // To handle closing any modal already visible when this modal is mounted, i.e. PopoverReportActionContextMenu
+ Modal.setCloseModal(onClose);
+ } else if (wasVisible && !isVisible) {
+ Modal.willAlertModalBecomeVisible(false);
+ Modal.setCloseModal(null);
+ }
+ }, [isVisible, wasVisible, onClose]);
useEffect(
() => () => {
// Only trigger onClose and setModalVisibility if the modal is unmounting while visible.
- if (isVisible) {
- hideModal(true);
- Modal.willAlertModalBecomeVisible(false);
+ if (!isVisibleRef.current) {
+ return;
}
-
+ hideModal(true);
+ Modal.willAlertModalBecomeVisible(false);
// To prevent closing any modal already unmounted when this modal still remains as visible state
Modal.setCloseModal(null);
},
diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.js
index 06a7f0b57b8e..3ccd61d32961 100644
--- a/src/components/MoneyReportHeader.js
+++ b/src/components/MoneyReportHeader.js
@@ -79,7 +79,6 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
return isManager && !isApproved && !isSettled;
}, [policyType, isManager, isApproved, isSettled]);
const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport);
- const shouldShowPaypal = Boolean(lodashGet(personalDetails, [moneyRequestReport.managerID, 'payPalMeAddress']));
const formattedAmount = CurrencyUtils.convertToDisplayString(reportTotal, moneyRequestReport.currency);
return (
@@ -99,11 +98,10 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)}
- enablePaymentsRoute={ROUTES.BANK_ACCOUNT_NEW}
+ enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS}
addBankAccountRoute={bankAccountRoute}
shouldShowPaymentOptions
style={[styles.pv2]}
@@ -128,11 +126,10 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
IOU.payMoneyRequest(paymentType, chatReport, moneyRequestReport)}
- enablePaymentsRoute={ROUTES.BANK_ACCOUNT_NEW}
+ enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS}
addBankAccountRoute={bankAccountRoute}
shouldShowPaymentOptions
formattedAmount={formattedAmount}
diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js
index cba2359eb257..4703ca099c7c 100755
--- a/src/components/MoneyRequestConfirmationList.js
+++ b/src/components/MoneyRequestConfirmationList.js
@@ -5,6 +5,7 @@ import {format} from 'date-fns';
import _ from 'underscore';
import {View} from 'react-native';
import lodashGet from 'lodash/get';
+import Text from './Text';
import styles from '../styles/styles';
import * as ReportUtils from '../libs/ReportUtils';
import * as OptionsListUtils from '../libs/OptionsListUtils';
@@ -30,11 +31,13 @@ import Image from './Image';
import useLocalize from '../hooks/useLocalize';
import * as ReceiptUtils from '../libs/ReceiptUtils';
import categoryPropTypes from './categoryPropTypes';
+import Switch from './Switch';
import tagPropTypes from './tagPropTypes';
import ConfirmedRoute from './ConfirmedRoute';
import transactionPropTypes from './transactionPropTypes';
import DistanceRequestUtils from '../libs/DistanceRequestUtils';
import * as IOU from '../libs/actions/IOU';
+import * as TransactionUtils from '../libs/TransactionUtils';
const propTypes = {
/** Callback to inform parent modal of success */
@@ -198,11 +201,16 @@ function MoneyRequestConfirmationList(props) {
const tagList = lodashGet(props.policyTags, [tagListKey, 'tags'], []);
const tagListName = lodashGet(props.policyTags, [tagListKey, 'name'], '');
const canUseTags = Permissions.canUseTags(props.betas);
+ const shouldShowTags = canUseTags && _.any(tagList, (tag) => tag.enabled);
- const formattedAmount = CurrencyUtils.convertToDisplayString(
- shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate) : props.iouAmount,
- props.isDistanceRequest ? currency : props.iouCurrencyCode,
- );
+ const hasRoute = TransactionUtils.hasRoute(transaction);
+ const isDistanceRequestWithoutRoute = props.isDistanceRequest && !hasRoute;
+ const formattedAmount = isDistanceRequestWithoutRoute
+ ? translate('common.tbd')
+ : CurrencyUtils.convertToDisplayString(
+ shouldCalculateDistanceAmount ? DistanceRequestUtils.getDistanceRequestAmount(distance, unit, rate) : props.iouAmount,
+ props.isDistanceRequest ? currency : props.iouCurrencyCode,
+ );
useEffect(() => {
if (!shouldCalculateDistanceAmount) {
@@ -230,7 +238,7 @@ function MoneyRequestConfirmationList(props) {
const splitOrRequestOptions = useMemo(() => {
let text;
- if (props.receiptPath) {
+ if (props.receiptPath || isDistanceRequestWithoutRoute) {
text = translate('iou.request');
} else {
const translationKey = props.hasMultipleParticipants ? 'iou.splitAmount' : 'iou.requestAmount';
@@ -242,7 +250,7 @@ function MoneyRequestConfirmationList(props) {
value: props.hasMultipleParticipants ? CONST.IOU.MONEY_REQUEST_TYPE.SPLIT : CONST.IOU.MONEY_REQUEST_TYPE.REQUEST,
},
];
- }, [props.hasMultipleParticipants, props.receiptPath, translate, formattedAmount]);
+ }, [props.hasMultipleParticipants, props.receiptPath, translate, formattedAmount, isDistanceRequestWithoutRoute]);
const selectedParticipants = useMemo(() => _.filter(props.selectedParticipants, (participant) => participant.selected), [props.selectedParticipants]);
const payeePersonalDetails = useMemo(() => props.payeePersonalDetails || props.currentUserPersonalDetails, [props.payeePersonalDetails, props.currentUserPersonalDetails]);
@@ -321,9 +329,9 @@ function MoneyRequestConfirmationList(props) {
if (!props.isDistanceRequest) {
return;
}
- const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(distance, unit, rate, currency, translate);
+ const distanceMerchant = DistanceRequestUtils.getDistanceMerchant(hasRoute, distance, unit, rate, currency, translate);
IOU.setMoneyRequestMerchant(distanceMerchant);
- }, [distance, unit, rate, currency, translate, props.isDistanceRequest]);
+ }, [hasRoute, distance, unit, rate, currency, translate, props.isDistanceRequest]);
/**
* @param {Object} option
@@ -385,13 +393,11 @@ function MoneyRequestConfirmationList(props) {
const shouldShowSettlementButton = props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.SEND;
const shouldDisableButton = selectedParticipants.length === 0;
- const recipient = props.selectedParticipants[0] || {};
return shouldShowSettlementButton ? (
);
- }, [confirm, props.selectedParticipants, props.bankAccountRoute, props.iouCurrencyCode, props.iouType, props.isReadOnly, props.policyID, selectedParticipants, splitOrRequestOptions]);
+ }, [confirm, props.bankAccountRoute, props.iouCurrencyCode, props.iouType, props.isReadOnly, props.policyID, selectedParticipants, splitOrRequestOptions]);
return (
)}
- {canUseTags && !!tagList && (
+ {shouldShowTags && (
)}
+ {canUseTags && !lodashGet(props.policy, 'disabledFields.defaultBillable', true) && (
+
+ {translate('common.billable')}
+
+
+ )}
>
)}
@@ -562,5 +579,8 @@ export default compose(
transaction: {
key: ({transactionID}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
},
+ policy: {
+ key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ },
}),
)(MoneyRequestConfirmationList);
diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js
index bdd7365b7893..7f1e58912128 100644
--- a/src/components/MoneyRequestHeader.js
+++ b/src/components/MoneyRequestHeader.js
@@ -9,8 +9,6 @@ import * as ReportUtils from '../libs/ReportUtils';
import * as Expensicons from './Icon/Expensicons';
import participantPropTypes from './participantPropTypes';
import styles from '../styles/styles';
-import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-import compose from '../libs/compose';
import Navigation from '../libs/Navigation/Navigation';
import ROUTES from '../ROUTES';
import ONYXKEYS from '../ONYXKEYS';
@@ -20,6 +18,8 @@ import useLocalize from '../hooks/useLocalize';
import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';
import * as TransactionUtils from '../libs/TransactionUtils';
import reportActionPropTypes from '../pages/home/report/reportActionPropTypes';
+import transactionPropTypes from './transactionPropTypes';
+import useWindowDimensions from '../hooks/useWindowDimensions';
const propTypes = {
/** The report currently being looked at */
@@ -34,7 +34,7 @@ const propTypes = {
/** Personal details so we can get the ones for the report participants */
personalDetails: PropTypes.objectOf(participantPropTypes).isRequired,
- /** Onyx Props */
+ /* Onyx Props */
/** Session info for the currently logged in user. */
session: PropTypes.shape({
/** Currently logged in user email */
@@ -47,13 +47,8 @@ const propTypes = {
/** The report action the transaction is tied to from the parent report */
parentReportAction: PropTypes.shape(reportActionPropTypes),
- /** The transaction from the parent report action */
- transaction: PropTypes.shape({
- /** The ID of the transaction */
- transactionID: PropTypes.string,
- }),
-
- ...windowDimensionsPropTypes,
+ /** All the data for the transaction */
+ transaction: transactionPropTypes,
};
const defaultProps = {
@@ -65,24 +60,22 @@ const defaultProps = {
transaction: {},
};
-function MoneyRequestHeader(props) {
+function MoneyRequestHeader({session, parentReport, report, parentReportAction, transaction, policy, personalDetails}) {
const {translate} = useLocalize();
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
- const moneyRequestReport = props.parentReport;
+ const moneyRequestReport = parentReport;
const isSettled = ReportUtils.isSettled(moneyRequestReport.reportID);
+ const {isSmallScreenWidth, windowWidth} = useWindowDimensions();
// Only the requestor can take delete the request, admins can only edit it.
- const isActionOwner = props.parentReportAction.actorAccountID === lodashGet(props.session, 'accountID', null);
- const report = props.report;
- report.ownerAccountID = lodashGet(props, ['parentReport', 'ownerAccountID'], null);
- report.ownerEmail = lodashGet(props, ['parentReport', 'ownerEmail'], '');
+ const isActionOwner = lodashGet(parentReportAction, 'actorAccountID') === lodashGet(session, 'accountID', null);
const deleteTransaction = useCallback(() => {
- IOU.deleteMoneyRequest(props.parentReportAction.originalMessage.IOUTransactionID, props.parentReportAction, true);
+ IOU.deleteMoneyRequest(lodashGet(parentReportAction, 'originalMessage.IOUTransactionID'), parentReportAction, true);
setIsDeleteModalVisible(false);
- }, [props.parentReportAction, setIsDeleteModalVisible]);
+ }, [parentReportAction, setIsDeleteModalVisible]);
- const isScanning = TransactionUtils.hasReceipt(props.transaction) && TransactionUtils.isReceiptBeingScanned(props.transaction);
+ const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);
return (
<>
@@ -94,15 +87,19 @@ function MoneyRequestHeader(props) {
threeDotsMenuItems={[
{
icon: Expensicons.Trashcan,
- text: translate('reportActionContextMenu.deleteAction', {action: props.parentReportAction}),
+ text: translate('reportActionContextMenu.deleteAction', {action: parentReportAction}),
onSelected: () => setIsDeleteModalVisible(true),
},
]}
- threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(props.windowWidth)}
- report={report}
- policy={props.policy}
- personalDetails={props.personalDetails}
- shouldShowBackButton={props.isSmallScreenWidth}
+ threeDotsAnchorPosition={styles.threeDotsPopoverOffsetNoCloseButton(windowWidth)}
+ report={{
+ ...report,
+ ownerAccountID: lodashGet(parentReport, 'ownerAccountID', null),
+ ownerEmail: lodashGet(parentReport, 'ownerEmail', null),
+ }}
+ policy={policy}
+ personalDetails={personalDetails}
+ shouldShowBackButton={isSmallScreenWidth}
onBackButtonPress={() => Navigation.goBack(ROUTES.HOME, false, true)}
/>
{isScanning && }
@@ -125,23 +122,19 @@ MoneyRequestHeader.displayName = 'MoneyRequestHeader';
MoneyRequestHeader.propTypes = propTypes;
MoneyRequestHeader.defaultProps = defaultProps;
-export default compose(
- withWindowDimensions,
- withOnyx({
- session: {
- key: ONYXKEYS.SESSION,
- },
- parentReport: {
- key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`,
- },
- parentReportAction: {
- key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${(report.parentReportID, report.parentReportActionID)}`,
- selector: (reportActions, props) => props && props.parentReport && reportActions && reportActions[props.parentReport.parentReportActionID],
- canEvict: false,
- },
- transaction: {
- key: ({report, parentReportActions}) =>
- `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportActions, [report.parentReportActionID, 'originalMessage', 'IOUTransactionID'], '')}`,
- },
- }),
-)(MoneyRequestHeader);
+export default withOnyx({
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ parentReport: {
+ key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID}`,
+ },
+ parentReportAction: {
+ key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${(report.parentReportID, report.parentReportActionID)}`,
+ selector: (reportActions, props) => props && props.parentReport && reportActions && reportActions[props.parentReport.parentReportActionID],
+ canEvict: false,
+ },
+ transaction: {
+ key: ({parentReportAction}) => `${ONYXKEYS.COLLECTION.TRANSACTION}${lodashGet(parentReportAction, 'originalMessage.IOUTransactionID', 0)}`,
+ },
+})(MoneyRequestHeader);
diff --git a/src/components/OfflineWithFeedback.js b/src/components/OfflineWithFeedback.js
index fb0411d24f4c..dae170dd1d5c 100644
--- a/src/components/OfflineWithFeedback.js
+++ b/src/components/OfflineWithFeedback.js
@@ -2,11 +2,7 @@ import _ from 'underscore';
import React from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
-import compose from '../libs/compose';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import {withNetwork} from './OnyxProvider';
import CONST from '../CONST';
-import networkPropTypes from './networkPropTypes';
import stylePropTypes from '../styles/stylePropTypes';
import styles from '../styles/styles';
import Tooltip from './Tooltip';
@@ -16,6 +12,8 @@ import * as StyleUtils from '../styles/StyleUtils';
import DotIndicatorMessage from './DotIndicatorMessage';
import shouldRenderOffscreen from '../libs/shouldRenderOffscreen';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
+import useLocalize from '../hooks/useLocalize';
+import useNetwork from '../hooks/useNetwork';
/**
* This component should be used when we are using the offline pattern B (offline with feedback).
@@ -46,9 +44,6 @@ const propTypes = {
/** The content that needs offline feedback */
children: PropTypes.node.isRequired,
- /** Information about the network */
- network: networkPropTypes.isRequired,
-
/** Additional styles to add after local styles. Applied to the parent container */
style: stylePropTypes,
@@ -58,7 +53,11 @@ const propTypes = {
/** Additional style object for the error row */
errorRowStyles: stylePropTypes,
- ...withLocalizePropTypes,
+ /** Whether applying strikethrough to the children should be disabled */
+ shouldDisableStrikeThrough: PropTypes.bool,
+
+ /** Whether to apply needsOffscreenAlphaCompositing prop to the children */
+ needsOffscreenAlphaCompositing: PropTypes.bool,
};
const defaultProps = {
@@ -71,6 +70,8 @@ const defaultProps = {
style: [],
contentContainerStyle: [],
errorRowStyles: [],
+ shouldDisableStrikeThrough: false,
+ needsOffscreenAlphaCompositing: false,
};
/**
@@ -92,17 +93,20 @@ function applyStrikeThrough(children) {
}
function OfflineWithFeedback(props) {
+ const {translate} = useLocalize();
+ const {isOffline} = useNetwork();
+
const hasErrors = !_.isEmpty(props.errors);
// Some errors have a null message. This is used to apply opacity only and to avoid showing redundant messages.
const errorMessages = _.omit(props.errors, (e) => e === null);
const hasErrorMessages = !_.isEmpty(errorMessages);
- const isOfflinePendingAction = props.network.isOffline && props.pendingAction;
+ const isOfflinePendingAction = isOffline && props.pendingAction;
const isUpdateOrDeleteError = hasErrors && (props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE);
const isAddError = hasErrors && props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD;
const needsOpacity = !props.shouldDisableOpacity && ((isOfflinePendingAction && !isUpdateOrDeleteError) || isAddError);
- const needsStrikeThrough = props.network.isOffline && props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
- const hideChildren = props.shouldHideOnDelete && !props.network.isOffline && props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && !hasErrors;
+ const needsStrikeThrough = !props.shouldDisableStrikeThrough && isOffline && props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
+ const hideChildren = props.shouldHideOnDelete && !isOffline && props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && !hasErrors;
let children = props.children;
// Apply strikethrough to children if needed, but skip it if we are not going to render them
@@ -126,12 +130,12 @@ function OfflineWithFeedback(props) {
messages={errorMessages}
type="error"
/>
-
+
@@ -146,4 +150,4 @@ OfflineWithFeedback.propTypes = propTypes;
OfflineWithFeedback.defaultProps = defaultProps;
OfflineWithFeedback.displayName = 'OfflineWithFeedback';
-export default compose(withLocalize, withNetwork())(OfflineWithFeedback);
+export default OfflineWithFeedback;
diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js
index 9b6875ccf8c2..5a40c28a86c9 100644
--- a/src/components/OptionsList/BaseOptionsList.js
+++ b/src/components/OptionsList/BaseOptionsList.js
@@ -174,7 +174,11 @@ function BaseOptionsList({
const renderItem = ({item, index, section}) => {
const isItemDisabled = isDisabled || section.isDisabled || !!item.isDisabled;
const isSelected = _.some(selectedOptions, (option) => {
- if (option.accountID === item.accountID) {
+ if (option.accountID && option.accountID === item.accountID) {
+ return true;
+ }
+
+ if (option.reportID && option.reportID === item.reportID) {
return true;
}
diff --git a/src/components/PopoverWithMeasuredContent.js b/src/components/PopoverWithMeasuredContent.js
index 492807274d1e..6b71b4a59055 100644
--- a/src/components/PopoverWithMeasuredContent.js
+++ b/src/components/PopoverWithMeasuredContent.js
@@ -149,7 +149,7 @@ function PopoverWithMeasuredContent(props) {
but we can't measure its dimensions without first rendering it.
*/
{props.children}
diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js
index 7eb0ee7286c9..40be99823ceb 100644
--- a/src/components/Pressable/PressableWithFeedback.js
+++ b/src/components/Pressable/PressableWithFeedback.js
@@ -58,19 +58,27 @@ const PressableWithFeedback = forwardRef((props, ref) => {
isExecuting={isExecuting}
onHoverIn={() => {
setIsHovered(true);
- if (props.onHoverIn) props.onHoverIn();
+ if (props.onHoverIn) {
+ props.onHoverIn();
+ }
}}
onHoverOut={() => {
setIsHovered(false);
- if (props.onHoverOut) props.onHoverOut();
+ if (props.onHoverOut) {
+ props.onHoverOut();
+ }
}}
onPressIn={() => {
setIsPressed(true);
- if (props.onPressIn) props.onPressIn();
+ if (props.onPressIn) {
+ props.onPressIn();
+ }
}}
onPressOut={() => {
setIsPressed(false);
- if (props.onPressOut) props.onPressOut();
+ if (props.onPressOut) {
+ props.onPressOut();
+ }
}}
onPress={(e) => {
singleExecution(() => props.onPress(e))();
diff --git a/src/components/QRShare/QRShareWithDownload/index.js b/src/components/QRShare/QRShareWithDownload/index.js
index 310122b96d40..665115823357 100644
--- a/src/components/QRShare/QRShareWithDownload/index.js
+++ b/src/components/QRShare/QRShareWithDownload/index.js
@@ -17,7 +17,9 @@ class QRShareWithDownload extends Component {
return new Promise((resolve, reject) => {
// eslint-disable-next-line es/no-optional-chaining
const svg = this.qrShareRef.current?.getSvg();
- if (svg == null) return reject();
+ if (svg == null) {
+ return reject();
+ }
svg.toDataURL((dataURL) => resolve(fileDownload(dataURL, getQrCodeFileName(this.props.title))));
});
diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
index 69ff37338c2d..b5046fbd59ce 100644
--- a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
+++ b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
@@ -80,7 +80,7 @@ function BaseQuickEmojiReactions(props) {
isContextMenu
onPressOpenPicker={props.onPressOpenPicker}
onWillShowPicker={props.onWillShowPicker}
- onSelectEmoji={props.onEmojiSelected}
+ onSelectEmoji={(emoji) => props.onEmojiSelected(emoji, props.emojiReactions)}
reportAction={props.reportAction}
/>
diff --git a/src/components/ReportActionItem/MoneyReportView.js b/src/components/ReportActionItem/MoneyReportView.js
index 68eecf11d5bf..f593d947f96c 100644
--- a/src/components/ReportActionItem/MoneyReportView.js
+++ b/src/components/ReportActionItem/MoneyReportView.js
@@ -15,6 +15,7 @@ import variables from '../../styles/variables';
import * as CurrencyUtils from '../../libs/CurrencyUtils';
import EmptyStateBackgroundImage from '../../../assets/images/empty-state_background-fade.png';
import useLocalize from '../../hooks/useLocalize';
+import SpacerView from '../SpacerView';
const propTypes = {
/** The report currently being looked at */
@@ -66,7 +67,10 @@ function MoneyReportView(props) {
- {props.shouldShowHorizontalRule && }
+
);
}
diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js
index ffa39d15dbb3..2afc6240f85d 100644
--- a/src/components/ReportActionItem/MoneyRequestPreview.js
+++ b/src/components/ReportActionItem/MoneyRequestPreview.js
@@ -163,24 +163,21 @@ function MoneyRequestPreview(props) {
const isScanning = hasReceipt && TransactionUtils.isReceiptBeingScanned(props.transaction);
const hasFieldErrors = TransactionUtils.hasMissingSmartscanFields(props.transaction);
const isDistanceRequest = TransactionUtils.isDistanceRequest(props.transaction);
+ const isSettled = ReportUtils.isSettled(props.iouReport);
// Show the merchant for IOUs and expenses only if they are custom or not related to scanning smartscan
const shouldShowMerchant =
!_.isEmpty(requestMerchant) && !props.isBillSplit && requestMerchant !== CONST.TRANSACTION.PARTIAL_TRANSACTION_MERCHANT && requestMerchant !== CONST.TRANSACTION.DEFAULT_MERCHANT;
const shouldShowDescription = !_.isEmpty(description) && !shouldShowMerchant;
- const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction.receipt.source, props.transaction.filename || props.transaction.receiptFilename || '')] : [];
+ const receiptImages = hasReceipt ? [ReceiptUtils.getThumbnailAndImageURIs(props.transaction.receipt.source, props.transaction.filename || '')] : [];
const getSettledMessage = () => {
switch (lodashGet(props.action, 'originalMessage.paymentType', '')) {
- case CONST.IOU.PAYMENT_TYPE.PAYPAL_ME:
- return props.translate('iou.settledPaypalMe');
- case CONST.IOU.PAYMENT_TYPE.ELSEWHERE:
- return props.translate('iou.settledElsewhere');
case CONST.IOU.PAYMENT_TYPE.EXPENSIFY:
return props.translate('iou.settledExpensify');
default:
- return '';
+ return props.translate('iou.settledElsewhere');
}
};
@@ -235,7 +232,7 @@ function MoneyRequestPreview(props) {
errorRowStyles={[styles.mbn1]}
needsOffscreenAlphaCompositing
>
-
+
{hasReceipt && (
{getPreviewHeaderText()}
- {Boolean(getSettledMessage()) && (
+ {isSettled && (
<>
{childContainer}
diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js
index 712c7ded6ab0..d8b15653d8af 100644
--- a/src/components/ReportActionItem/MoneyRequestView.js
+++ b/src/components/ReportActionItem/MoneyRequestView.js
@@ -27,6 +27,7 @@ import Image from '../Image';
import ReportActionItemImage from './ReportActionItemImage';
import * as TransactionUtils from '../../libs/TransactionUtils';
import OfflineWithFeedback from '../OfflineWithFeedback';
+import SpacerView from '../SpacerView';
const propTypes = {
/** The report currently being looked at */
@@ -91,7 +92,7 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans
let hasErrors = false;
if (hasReceipt) {
receiptURIs = ReceiptUtils.getThumbnailAndImageURIs(transaction.receipt.source, transaction.filename);
- hasErrors = TransactionUtils.hasMissingSmartscanFields(transaction);
+ hasErrors = canEdit && TransactionUtils.hasMissingSmartscanFields(transaction);
}
const isDistanceRequest = TransactionUtils.isDistanceRequest(transaction);
@@ -169,7 +170,10 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans
subtitleTextStyle={styles.textLabelError}
/>
- {shouldShowHorizontalRule && }
+
);
}
diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js
index 5f8151b385a2..1350c62bda88 100644
--- a/src/components/ReportActionItem/ReportPreview.js
+++ b/src/components/ReportActionItem/ReportPreview.js
@@ -120,9 +120,7 @@ function ReportPreview(props) {
const isScanning = hasReceipts && ReportUtils.areAllRequestsBeingSmartScanned(props.iouReportID, props.action);
const hasErrors = hasReceipts && ReportUtils.hasMissingSmartscanFields(props.iouReportID);
const lastThreeTransactionsWithReceipts = ReportUtils.getReportPreviewDisplayTransactions(props.action);
- const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, ({receipt, filename, receiptFilename}) =>
- ReceiptUtils.getThumbnailAndImageURIs(receipt.source, filename || receiptFilename || ''),
- );
+ const lastThreeReceipts = _.map(lastThreeTransactionsWithReceipts, ({receipt, filename}) => ReceiptUtils.getThumbnailAndImageURIs(receipt.source, filename || ''));
const hasOnlyOneReceiptRequest = numberOfRequests === 1 && hasReceipts;
const previewSubtitle = hasOnlyOneReceiptRequest
@@ -229,7 +227,7 @@ function ReportPreview(props) {
chatReportID={props.chatReportID}
iouReport={props.iouReport}
onPress={(paymentType) => IOU.payMoneyRequest(paymentType, props.chatReport, props.iouReport)}
- enablePaymentsRoute={ROUTES.BANK_ACCOUNT_NEW}
+ enablePaymentsRoute={ROUTES.ENABLE_PAYMENTS}
addBankAccountRoute={bankAccountRoute}
style={[styles.requestPreviewBox]}
/>
diff --git a/src/components/ReportActionItem/TaskAction.js b/src/components/ReportActionItem/TaskAction.js
index c0b60ad996db..9d32fa7a1e77 100644
--- a/src/components/ReportActionItem/TaskAction.js
+++ b/src/components/ReportActionItem/TaskAction.js
@@ -1,13 +1,10 @@
import React from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
-import {withOnyx} from 'react-native-onyx';
import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
import Text from '../Text';
import styles from '../../styles/styles';
-import CONST from '../../CONST';
+import * as Task from '../../libs/actions/Task';
const propTypes = {
/** Name of the reportAction action */
@@ -17,60 +14,20 @@ const propTypes = {
// eslint-disable-next-line react/no-unused-prop-types -- This is used in the withOnyx HOC
taskReportID: PropTypes.string.isRequired,
- /* Onyx Props */
- taskReport: PropTypes.shape({
- /** Title of the task */
- reportName: PropTypes.string,
-
- /** AccountID of the manager in this iou report */
- managerID: PropTypes.number,
-
- /** AccountID of the creator of this iou report */
- ownerAccountID: PropTypes.number,
- }),
-
...withLocalizePropTypes,
};
-const defaultProps = {
- taskReport: {},
-};
function TaskAction(props) {
- const taskReportName = props.taskReport.reportName || '';
-
- let taskStatusText = '';
- switch (props.actionName) {
- case CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED:
- taskStatusText = props.translate('task.messages.completed');
- break;
- case CONST.REPORT.ACTIONS.TYPE.TASKCANCELLED:
- taskStatusText = props.translate('task.messages.canceled');
- break;
- case CONST.REPORT.ACTIONS.TYPE.TASKREOPENED:
- taskStatusText = props.translate('task.messages.reopened');
- break;
- default:
- taskStatusText = props.translate('task.task');
- }
-
return (
<>
- {`${taskStatusText} ${taskReportName}`}
+ {Task.getTaskReportActionMessage(props.actionName, props.taskReportID, false)}
>
);
}
TaskAction.propTypes = propTypes;
-TaskAction.defaultProps = defaultProps;
TaskAction.displayName = 'TaskAction';
-export default compose(
- withLocalize,
- withOnyx({
- taskReport: {
- key: ({taskReportID}) => `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`,
- },
- }),
-)(TaskAction);
+export default withLocalize(TaskAction);
diff --git a/src/components/ReportActionItem/TaskPreview.js b/src/components/ReportActionItem/TaskPreview.js
index ca4103624440..d0181e3d736a 100644
--- a/src/components/ReportActionItem/TaskPreview.js
+++ b/src/components/ReportActionItem/TaskPreview.js
@@ -72,6 +72,11 @@ function TaskPreview(props) {
const assigneeDisplayName = lodashGet(props.personalDetailsList, [taskAssigneeAccountID, 'displayName'], '');
const taskAssignee = assigneeLogin || assigneeDisplayName;
const htmlForTaskPreview = taskAssignee ? `@${taskAssignee} ${taskTitle}` : `${taskTitle}`;
+ const isDeletedParentAction = ReportUtils.isCanceledTaskReport(props.taskReport, props.action);
+
+ if (isDeletedParentAction) {
+ return ${props.translate('parentReportAction.deletedTask')}`} />;
+ }
return (
diff --git a/src/components/ReportActionItem/TaskView.js b/src/components/ReportActionItem/TaskView.js
index 8c6432a79878..ae77a18b980f 100644
--- a/src/components/ReportActionItem/TaskView.js
+++ b/src/components/ReportActionItem/TaskView.js
@@ -27,6 +27,7 @@ import getButtonState from '../../libs/getButtonState';
import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction';
import * as Session from '../../libs/actions/Session';
import * as Expensicons from '../Icon/Expensicons';
+import SpacerView from '../SpacerView';
const propTypes = {
/** The report currently being looked at */
@@ -50,7 +51,8 @@ function TaskView(props) {
const isOpen = ReportUtils.isOpenTaskReport(props.report);
const isCanceled = ReportUtils.isCanceledTaskReport(props.report);
const canModifyTask = Task.canModifyTask(props.report, props.currentUserPersonalDetails.accountID);
- const disableState = !canModifyTask || !isOpen;
+ const disableState = !canModifyTask || isCanceled;
+ const isDisableInteractive = !canModifyTask || !isOpen;
return (
(
{
+ if (isDisableInteractive) {
+ return;
+ }
if (e && e.type === 'click') {
e.currentTarget.blur();
}
Navigation.navigate(ROUTES.getTaskReportTitleRoute(props.report.reportID));
})}
- style={({pressed}) => [styles.ph5, styles.pv2, StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed, false, disableState), true)]}
+ style={({pressed}) => [
+ styles.ph5,
+ styles.pv2,
+ StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed, false, disableState, !isDisableInteractive), true),
+ isDisableInteractive && !disableState && styles.cursorDefault,
+ ]}
ref={props.forwardedRef}
disabled={disableState}
accessibilityLabel={taskTitle || props.translate('task.task')}
@@ -128,6 +138,7 @@ function TaskView(props) {
wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]}
shouldGreyOutWhenDisabled={false}
numberOfLinesTitle={0}
+ interactive={!isDisableInteractive}
/>
{props.report.managerID ? (
@@ -145,6 +156,7 @@ function TaskView(props) {
wrapperStyle={[styles.pv2]}
isSmallAvatarSubscriptMenu
shouldGreyOutWhenDisabled={false}
+ interactive={!isDisableInteractive}
/>
) : (
@@ -155,10 +167,14 @@ function TaskView(props) {
disabled={disableState}
wrapperStyle={[styles.pv2]}
shouldGreyOutWhenDisabled={false}
+ interactive={!isDisableInteractive}
/>
)}
- {props.shouldShowHorizontalRule && }
+
);
}
diff --git a/src/components/ReportActionsSkeletonView/SkeletonViewLines.js b/src/components/ReportActionsSkeletonView/SkeletonViewLines.js
index ddaa46e0b731..e4432ceb2309 100644
--- a/src/components/ReportActionsSkeletonView/SkeletonViewLines.js
+++ b/src/components/ReportActionsSkeletonView/SkeletonViewLines.js
@@ -31,20 +31,20 @@ function SkeletonViewLines(props) {
r="20"
/>
{props.numberOfRows > 1 && (
2 && (
(method.value === paymentMethod ? 0 : 1));
}
return buttonOptions;
- }, [betas, currency, formattedAmount, iouReport, nvp_lastPaymentMethod, policyID, shouldShowPaymentOptions, shouldShowPaypal, translate]);
+ }, [betas, currency, formattedAmount, iouReport, nvp_lastPaymentMethod, policyID, shouldShowPaymentOptions, translate]);
const selectPaymentType = (event, iouPaymentType, triggerKYCFlow) => {
if (iouPaymentType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY || iouPaymentType === CONST.IOU.PAYMENT_TYPE.VBBA) {
diff --git a/src/components/SignInButtons/AppleSignIn/index.android.js b/src/components/SignInButtons/AppleSignIn/index.android.js
index 83a99683b178..48d2bf3cc861 100644
--- a/src/components/SignInButtons/AppleSignIn/index.android.js
+++ b/src/components/SignInButtons/AppleSignIn/index.android.js
@@ -39,7 +39,9 @@ function AppleSignIn() {
appleSignInRequest()
.then((token) => Session.beginAppleSignIn(token))
.catch((e) => {
- if (e.message === appleAuthAndroid.Error.SIGNIN_CANCELLED) return null;
+ if (e.message === appleAuthAndroid.Error.SIGNIN_CANCELLED) {
+ return null;
+ }
Log.alert('[Apple Sign In] Apple authentication failed', e);
});
};
diff --git a/src/components/SignInButtons/AppleSignIn/index.desktop.js b/src/components/SignInButtons/AppleSignIn/index.desktop.js
index 425e88ddf930..52ff3ef710b0 100644
--- a/src/components/SignInButtons/AppleSignIn/index.desktop.js
+++ b/src/components/SignInButtons/AppleSignIn/index.desktop.js
@@ -14,7 +14,7 @@ const appleSignInWebRouteForDesktopFlow = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}
*/
function AppleSignIn() {
return (
-
+
{
window.open(appleSignInWebRouteForDesktopFlow);
diff --git a/src/components/SignInButtons/AppleSignIn/index.ios.js b/src/components/SignInButtons/AppleSignIn/index.ios.js
index 681eebb298c5..0c9a8c9e8211 100644
--- a/src/components/SignInButtons/AppleSignIn/index.ios.js
+++ b/src/components/SignInButtons/AppleSignIn/index.ios.js
@@ -37,7 +37,9 @@ function AppleSignIn() {
appleSignInRequest()
.then((token) => Session.beginAppleSignIn(token))
.catch((e) => {
- if (e.code === appleAuth.Error.CANCELED) return null;
+ if (e.code === appleAuth.Error.CANCELED) {
+ return null;
+ }
Log.alert('[Apple Sign In] Apple authentication failed', e);
});
};
diff --git a/src/components/SignInButtons/AppleSignIn/index.website.js b/src/components/SignInButtons/AppleSignIn/index.website.js
index 41c8f2afd4d5..7046de5068b1 100644
--- a/src/components/SignInButtons/AppleSignIn/index.website.js
+++ b/src/components/SignInButtons/AppleSignIn/index.website.js
@@ -55,7 +55,9 @@ const successListener = (event) => {
};
const failureListener = (event) => {
- if (!event.detail || event.detail.error === 'popup_closed_by_user') return null;
+ if (!event.detail || event.detail.error === 'popup_closed_by_user') {
+ return null;
+ }
Log.warn(`Apple sign-in failed: ${event.detail}`);
};
@@ -126,7 +128,9 @@ const SingletonAppleSignInButtonWithFocus = withNavigationFocus(SingletonAppleSi
function AppleSignIn({isDesktopFlow}) {
const [scriptLoaded, setScriptLoaded] = useState(false);
useEffect(() => {
- if (window.appleAuthScriptLoaded) return;
+ if (window.appleAuthScriptLoaded) {
+ return;
+ }
const localeCode = getUserLanguage();
const script = document.createElement('script');
diff --git a/src/components/SignInButtons/GoogleSignIn/index.desktop.js b/src/components/SignInButtons/GoogleSignIn/index.desktop.js
index bdba2052d664..95a78f34614b 100644
--- a/src/components/SignInButtons/GoogleSignIn/index.desktop.js
+++ b/src/components/SignInButtons/GoogleSignIn/index.desktop.js
@@ -17,7 +17,7 @@ const googleSignInWebRouteForDesktopFlow = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL
*/
function GoogleSignIn() {
return (
-
+
{
window.open(googleSignInWebRouteForDesktopFlow);
diff --git a/src/components/SpacerView.js b/src/components/SpacerView.js
new file mode 100644
index 000000000000..3b81bbfa0dc5
--- /dev/null
+++ b/src/components/SpacerView.js
@@ -0,0 +1,49 @@
+import React from 'react';
+import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
+import PropTypes from 'prop-types';
+import * as StyleUtils from '../styles/StyleUtils';
+import stylePropTypes from '../styles/stylePropTypes';
+import CONST from '../CONST';
+
+const propTypes = {
+ /**
+ * Should we show the spacer
+ */
+ shouldShow: PropTypes.bool.isRequired,
+
+ /**
+ * Array of style objects
+ * @default []
+ */
+ style: stylePropTypes,
+};
+
+const defaultProps = {
+ style: [],
+};
+
+function SpacerView({shouldShow = true, style = []}) {
+ const marginVertical = useSharedValue(CONST.HORIZONTAL_SPACER.DEFAULT_MARGIN_VERTICAL);
+ const borderBottomWidth = useSharedValue(CONST.HORIZONTAL_SPACER.DEFAULT_BORDER_BOTTOM_WIDTH);
+ const animatedStyles = useAnimatedStyle(() => ({
+ marginVertical: marginVertical.value,
+ borderBottomWidth: borderBottomWidth.value,
+ }));
+
+ React.useEffect(() => {
+ const duration = CONST.ANIMATED_TRANSITION;
+ const values = {
+ marginVertical: shouldShow ? CONST.HORIZONTAL_SPACER.DEFAULT_MARGIN_VERTICAL : CONST.HORIZONTAL_SPACER.HIDDEN_MARGIN_VERTICAL,
+ borderBottomWidth: shouldShow ? CONST.HORIZONTAL_SPACER.DEFAULT_BORDER_BOTTOM_WIDTH : CONST.HORIZONTAL_SPACER.HIDDEN_BORDER_BOTTOM_WIDTH,
+ };
+ marginVertical.value = withTiming(values.marginVertical, {duration});
+ borderBottomWidth.value = withTiming(values.borderBottomWidth, {duration});
+ }, [shouldShow, borderBottomWidth, marginVertical]);
+
+ return ;
+}
+
+SpacerView.displayName = 'SpacerView';
+SpacerView.propTypes = propTypes;
+SpacerView.defaultProps = defaultProps;
+export default SpacerView;
diff --git a/src/components/TagPicker/index.js b/src/components/TagPicker/index.js
index 25021bd817d7..c46ca1b57b22 100644
--- a/src/components/TagPicker/index.js
+++ b/src/components/TagPicker/index.js
@@ -1,62 +1,58 @@
-import React, {useMemo} from 'react';
+import React, {useMemo, useState} from 'react';
import _ from 'underscore';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
+import CONST from '../../CONST';
import ONYXKEYS from '../../ONYXKEYS';
import styles from '../../styles/styles';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
import useLocalize from '../../hooks/useLocalize';
import * as OptionsListUtils from '../../libs/OptionsListUtils';
import OptionsSelector from '../OptionsSelector';
import {propTypes, defaultProps} from './tagPickerPropTypes';
-function TagPicker({policyTags, reportID, tag, iouType, iou}) {
+function TagPicker({selectedTag, tag, policyTags, policyRecentlyUsedTags, onSubmit}) {
const {translate} = useLocalize();
+ const [searchValue, setSearchValue] = useState('');
+
+ const policyRecentlyUsedTagsList = lodashGet(policyRecentlyUsedTags, tag, []);
+ const policyTagList = lodashGet(policyTags, [tag, 'tags'], {});
+ const policyTagsCount = _.size(_.filter(policyTagList, (policyTag) => policyTag.enabled));
+ const isTagsCountBelowThreshold = policyTagsCount < CONST.TAG_LIST_THRESHOLD;
+
+ const shouldShowTextInput = !isTagsCountBelowThreshold;
const selectedOptions = useMemo(() => {
- if (!iou.tag) {
+ if (!selectedTag) {
return [];
}
return [
{
- name: iou.tag,
+ name: selectedTag,
enabled: true,
+ accountID: null,
},
];
- }, [iou.tag]);
-
- // Only shows one section, which will be the default behavior if there are
- // less than 8 policy tags
- // TODO: support sections with search
- const sections = useMemo(() => {
- const tagList = _.chain(lodashGet(policyTags, [tag, 'tags'], {}))
- .values()
- .map((t) => ({
- text: t.name,
- keyForList: t.name,
- tooltipText: t.name,
- }))
- .value();
+ }, [selectedTag]);
- return [
- {
- data: tagList,
- },
- ];
- }, [policyTags, tag]);
+ const initialFocusedIndex = useMemo(() => {
+ if (isTagsCountBelowThreshold && selectedOptions.length > 0) {
+ return _.chain(policyTagList)
+ .values()
+ .findIndex((policyTag) => policyTag.name === selectedOptions[0].name, true)
+ .value();
+ }
- const headerMessage = OptionsListUtils.getHeaderMessage(lodashGet(sections, '[0].data.length', 0) > 0, false, '');
+ return 0;
+ }, [policyTagList, selectedOptions, isTagsCountBelowThreshold]);
- const navigateBack = () => {
- Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID));
- };
+ const sections = useMemo(
+ () =>
+ OptionsListUtils.getFilteredOptions({}, {}, [], searchValue, selectedOptions, [], false, false, false, {}, [], true, policyTagList, policyRecentlyUsedTagsList, false).tagOptions,
+ [searchValue, selectedOptions, policyTagList, policyRecentlyUsedTagsList],
+ );
- const updateTag = () => {
- // TODO: add logic to save the selected tag
- navigateBack();
- };
+ const headerMessage = OptionsListUtils.getHeaderMessage(lodashGet(sections, '[0].data.length', 0) > 0, false, '');
return (
);
}
@@ -84,7 +84,4 @@ export default withOnyx({
policyRecentlyUsedTags: {
key: ({policyID}) => `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS}${policyID}`,
},
- iou: {
- key: ONYXKEYS.IOU,
- },
})(TagPicker);
diff --git a/src/components/TagPicker/tagPickerPropTypes.js b/src/components/TagPicker/tagPickerPropTypes.js
index ad57a0409f15..a5d94605a76a 100644
--- a/src/components/TagPicker/tagPickerPropTypes.js
+++ b/src/components/TagPicker/tagPickerPropTypes.js
@@ -1,22 +1,18 @@
import PropTypes from 'prop-types';
import tagPropTypes from '../tagPropTypes';
-import {iouPropTypes, iouDefaultProps} from '../../pages/iou/propTypes';
const propTypes = {
- /** The report ID of the IOU */
- reportID: PropTypes.string.isRequired,
-
/** The policyID we are getting tags for */
policyID: PropTypes.string.isRequired,
+ /** The selected tag of the money request */
+ selectedTag: PropTypes.string.isRequired,
+
/** The name of tag list we are getting tags for */
tag: PropTypes.string.isRequired,
- /** The type of IOU report, i.e. bill, request, send */
- iouType: PropTypes.string.isRequired,
-
/** Callback to submit the selected tag */
- onSubmit: PropTypes.func,
+ onSubmit: PropTypes.func.isRequired,
/* Onyx Props */
/** Collection of tags attached to a policy */
@@ -29,15 +25,11 @@ const propTypes = {
/** List of recently used tags */
policyRecentlyUsedTags: PropTypes.objectOf(PropTypes.arrayOf(PropTypes.string)),
-
- /** Holds data related to Money Request view state, rather than the underlying Money Request data. */
- iou: iouPropTypes,
};
const defaultProps = {
policyTags: {},
policyRecentlyUsedTags: {},
- iou: iouDefaultProps,
};
export {propTypes, defaultProps};
diff --git a/src/components/TextInput/index.js b/src/components/TextInput/index.js
index 48a92f081200..6cefe04e71a1 100644
--- a/src/components/TextInput/index.js
+++ b/src/components/TextInput/index.js
@@ -30,7 +30,9 @@ function TextInput(props) {
});
return () => {
- if (!removeVisibilityListenerRef.current) return;
+ if (!removeVisibilityListenerRef.current) {
+ return;
+ }
removeVisibilityListenerRef.current();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
diff --git a/src/components/ThreeDotsMenu/index.js b/src/components/ThreeDotsMenu/index.js
index b5637a4f3879..f0cee6fdea2f 100644
--- a/src/components/ThreeDotsMenu/index.js
+++ b/src/components/ThreeDotsMenu/index.js
@@ -45,6 +45,9 @@ const propTypes = {
horizontal: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL)),
vertical: PropTypes.oneOf(_.values(CONST.MODAL.ANCHOR_ORIGIN_VERTICAL)),
}),
+
+ /** Whether the popover menu should overlay the current view */
+ shouldOverlay: PropTypes.bool,
};
const defaultProps = {
@@ -57,9 +60,10 @@ const defaultProps = {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.LEFT,
vertical: CONST.MODAL.ANCHOR_ORIGIN_VERTICAL.TOP, // we assume that popover menu opens below the button, anchor is at TOP
},
+ shouldOverlay: false,
};
-function ThreeDotsMenu({iconTooltip, icon, iconFill, iconStyles, onIconPress, menuItems, anchorPosition, anchorAlignment}) {
+function ThreeDotsMenu({iconTooltip, icon, iconFill, iconStyles, onIconPress, menuItems, anchorPosition, anchorAlignment, shouldOverlay}) {
const [isPopupMenuVisible, setPopupMenuVisible] = useState(false);
const buttonRef = useRef(null);
const {translate} = useLocalize();
@@ -106,7 +110,7 @@ function ThreeDotsMenu({iconTooltip, icon, iconFill, iconStyles, onIconPress, me
anchorAlignment={anchorAlignment}
onItemSelected={hidePopoverMenu}
menuItems={menuItems}
- withoutOverlay
+ withoutOverlay={!shouldOverlay}
anchorRef={buttonRef}
/>
>
diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js
index 398df07649cf..f60982f52dd4 100644
--- a/src/components/Tooltip/index.js
+++ b/src/components/Tooltip/index.js
@@ -154,6 +154,7 @@ function Tooltip(props) {
{children}
diff --git a/src/components/Tooltip/tooltipPropTypes.js b/src/components/Tooltip/tooltipPropTypes.js
index af18c4cfa412..2ddf8120d58c 100644
--- a/src/components/Tooltip/tooltipPropTypes.js
+++ b/src/components/Tooltip/tooltipPropTypes.js
@@ -28,6 +28,9 @@ const propTypes = {
/** Unique key of renderTooltipContent to rerender the tooltip when one of the key changes */
renderTooltipContentKey: PropTypes.arrayOf(PropTypes.string),
+
+ /** passes this down to Hoverable component to decide whether to handle the scroll behaviour to show hover once the scroll ends */
+ shouldHandleScroll: PropTypes.bool,
};
const defaultProps = {
@@ -38,6 +41,7 @@ const defaultProps = {
numberOfLines: CONST.TOOLTIP_MAX_LINES,
renderTooltipContent: undefined,
renderTooltipContentKey: [],
+ shouldHandleScroll: false,
};
export {propTypes, defaultProps};
diff --git a/src/components/UserDetailsTooltip/index.web.js b/src/components/UserDetailsTooltip/index.web.js
index 5fdae15184ac..1a78459d30a6 100644
--- a/src/components/UserDetailsTooltip/index.web.js
+++ b/src/components/UserDetailsTooltip/index.web.js
@@ -66,6 +66,7 @@ function UserDetailsTooltip(props) {
shiftHorizontal={props.shiftHorizontal}
renderTooltipContent={renderTooltipContent}
renderTooltipContentKey={[userDisplayName, userLogin]}
+ shouldHandleScroll
>
{props.children}
diff --git a/src/components/optionPropTypes.js b/src/components/optionPropTypes.js
index bb1a7a073b61..709298036f07 100644
--- a/src/components/optionPropTypes.js
+++ b/src/components/optionPropTypes.js
@@ -68,6 +68,4 @@ export default PropTypes.shape({
brickRoadIndicator: PropTypes.oneOf([CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR, '']),
phoneNumber: PropTypes.string,
-
- payPalMeAddress: PropTypes.string,
});
diff --git a/src/components/paypalMeDataPropTypes.js b/src/components/paypalMeDataPropTypes.js
deleted file mode 100644
index 5498186748a5..000000000000
--- a/src/components/paypalMeDataPropTypes.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import PropTypes from 'prop-types';
-
-export default PropTypes.shape({
- /** This is always 'PayPal.me' */
- title: PropTypes.string,
-
- /** The paypalMe address */
- description: PropTypes.string,
-
- /** This is always 'payPalMe' */
- methodID: PropTypes.string,
-
- /** This is always 'payPalMe' */
- accountType: PropTypes.string,
-});
diff --git a/src/components/withWindowDimensions/index.js b/src/components/withWindowDimensions/index.js
index a3836fa99e6b..37d5c94688a2 100644
--- a/src/components/withWindowDimensions/index.js
+++ b/src/components/withWindowDimensions/index.js
@@ -1,5 +1,6 @@
import React, {forwardRef, createContext, useState, useEffect} from 'react';
import PropTypes from 'prop-types';
+import lodashDebounce from 'lodash/debounce';
import {Dimensions} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import getComponentDisplayName from '../../libs/getComponentDisplayName';
@@ -44,14 +45,15 @@ function WindowDimensionsProvider(props) {
useEffect(() => {
const onDimensionChange = (newDimensions) => {
const {window} = newDimensions;
-
setWindowDimension({
windowHeight: window.height,
windowWidth: window.width,
});
};
- const dimensionsEventListener = Dimensions.addEventListener('change', onDimensionChange);
+ const onDimensionChangeDebounce = lodashDebounce(onDimensionChange, 300);
+
+ const dimensionsEventListener = Dimensions.addEventListener('change', onDimensionChangeDebounce);
return () => {
if (!dimensionsEventListener) {
diff --git a/src/languages/en.ts b/src/languages/en.ts
index c31e39319a98..f7c028d2a106 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -25,7 +25,6 @@ import type {
ReportArchiveReasonsPolicyDeletedParams,
RequestCountParams,
SettleExpensifyCardParams,
- SettlePaypalMeParams,
RequestAmountParams,
SplitAmountParams,
AmountEachParams,
@@ -37,7 +36,6 @@ import type {
WaitingOnBankAccountParams,
SettledAfterAddedBankAccountParams,
PaidElsewhereWithAmountParams,
- PaidUsingPaypalWithAmountParams,
PaidWithExpensifyWithAmountParams,
ThreadRequestReportNameParams,
ThreadSentMoneyReportNameParams,
@@ -71,6 +69,8 @@ import type {
SetTheRequestParams,
UpdatedTheRequestParams,
RemovedTheRequestParams,
+ FormattedMaxLengthParams,
+ RequestedAmountMessageParams,
TagSelectionParams,
TranslationBase,
} from './types';
@@ -206,7 +206,6 @@ export default {
done: 'Done',
more: 'More',
debitCard: 'Debit card',
- payPalMe: 'PayPal.me',
bankAccount: 'Bank account',
join: 'Join',
decline: 'Decline',
@@ -244,6 +243,7 @@ export default {
showMore: 'Show more',
merchant: 'Merchant',
category: 'Category',
+ billable: 'Billable',
tag: 'Tag',
receipt: 'Receipt',
replace: 'Replace',
@@ -254,6 +254,7 @@ export default {
kilometers: 'kilometers',
recent: 'Recent',
all: 'All',
+ tbd: 'TBD',
},
anonymousReportFooter: {
logoTagline: 'Join the discussion.',
@@ -282,6 +283,7 @@ export default {
composer: {
noExtensionFoundForMimeType: 'No extension found for mime type',
problemGettingImageYouPasted: 'There was a problem getting the image you pasted',
+ commentExceededMaxLength: ({formattedMaxLength}: FormattedMaxLengthParams) => `The maximum comment length is ${formattedMaxLength} characters.`,
},
baseUpdateAppModal: {
updateApp: 'Update app',
@@ -513,11 +515,10 @@ export default {
deleteConfirmation: 'Are you sure that you want to delete this request?',
settledExpensify: 'Paid',
settledElsewhere: 'Paid elsewhere',
- settledPaypalMe: 'Paid using Paypal.me',
settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => `Pay ${formattedAmount} with Expensify`,
payElsewhere: 'Pay elsewhere',
- settlePaypalMe: ({formattedAmount}: SettlePaypalMeParams) => `Pay ${formattedAmount} with PayPal.me`,
requestAmount: ({amount}: RequestAmountParams) => `request ${amount}`,
+ requestedAmount: ({formattedAmount, comment}: RequestedAmountMessageParams) => `requested ${formattedAmount}${comment ? ` for ${comment}` : ''}`,
splitAmount: ({amount}: SplitAmountParams) => `split ${amount}`,
amountEach: ({amount}: AmountEachParams) => `${amount} each`,
payerOwesAmount: ({payer, amount}: PayerOwesAmountParams) => `${payer} owes ${amount}`,
@@ -529,9 +530,8 @@ export default {
waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `started settling up, payment is held until ${submitterDisplayName} adds a bank account`,
settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) =>
`${submitterDisplayName} added a bank account. The ${amount} payment has been made.`,
- paidElsewhereWithAmount: ({amount}: PaidElsewhereWithAmountParams) => `paid ${amount} elsewhere`,
- paidUsingPaypalWithAmount: ({amount}: PaidUsingPaypalWithAmountParams) => `paid ${amount} using Paypal.me`,
- paidWithExpensifyWithAmount: ({amount}: PaidWithExpensifyWithAmountParams) => `paid ${amount} with Expensify`,
+ paidElsewhereWithAmount: ({payer, amount}: PaidElsewhereWithAmountParams) => `${payer} paid ${amount} elsewhere`,
+ paidWithExpensifyWithAmount: ({payer, amount}: PaidWithExpensifyWithAmountParams) => `${payer} paid ${amount} using Expensify`,
noReimbursableExpenses: 'This report has an invalid amount',
pendingConversionMessage: "Total will update when you're back online",
changedTheRequest: 'changed the request',
@@ -543,6 +543,7 @@ export default {
threadSentMoneyReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} sent${comment ? ` for ${comment}` : ''}`,
tagSelection: ({tagName}: TagSelectionParams) => `Select a ${tagName} to add additional organization to your money`,
error: {
+ invalidAmount: 'Please enter a valid amount before continuing.',
invalidSplit: 'Split amounts do not equal total amount',
other: 'Unexpected error, please try again later',
genericCreateFailureMessage: 'Unexpected error requesting money, please try again later',
@@ -568,6 +569,8 @@ export default {
uploadPhoto: 'Upload photo',
removePhoto: 'Remove photo',
editImage: 'Edit photo',
+ viewPhoto: 'View photo',
+ imageUploadFailed: 'Image upload failed',
deleteWorkspaceError: 'Sorry, there was an unexpected problem deleting your workspace avatar.',
sizeExceeded: ({maxUploadSizeInMB}: SizeExceededParams) => `The selected image exceeds the maximum upload size of ${maxUploadSizeInMB}MB.`,
resolutionConstraints: ({minHeightInPx, minWidthInPx, maxHeightInPx, maxWidthInPx}: ResolutionConstraintsParams) =>
@@ -587,6 +590,7 @@ export default {
online: 'Online',
offline: 'Offline',
syncing: 'Syncing',
+ profileAvatar: 'Profile avatar',
},
loungeAccessPage: {
loungeAccess: 'Lounge access',
@@ -728,6 +732,7 @@ export default {
keepCodesSafe: 'Keep these recovery codes safe!',
codesLoseAccess:
'If you lose access to your authenticator app and don’t have these codes, you will lose access to your account. \n\nNote: Setting up two-factor authentication will log you out of all other active sessions.',
+ errorStepCodes: 'Please copy or download codes before continuing.',
stepVerify: 'Verify',
scanCode: 'Scan the QR code using your',
authenticatorApp: 'authenticator app',
@@ -739,6 +744,15 @@ export default {
copy: 'Copy',
disable: 'Disable',
},
+ recoveryCodeForm: {
+ error: {
+ pleaseFillRecoveryCode: 'Please enter your recovery code',
+ incorrectRecoveryCode: 'Incorrect recovery code. Please try again.',
+ },
+ useRecoveryCode: 'Use recovery code',
+ recoveryCode: 'Recovery code',
+ use2fa: 'Use two-factor authentication code',
+ },
twoFactorAuthForm: {
error: {
pleaseFillTwoFactorAuth: 'Please enter your two-factor authentication code',
@@ -755,18 +769,7 @@ export default {
sharedNoteMessage: 'Keep notes about this chat here. Expensify employees and other users on the team.expensify.com domain can view these notes.',
notesUnavailable: 'No notes found for the user',
composerLabel: 'Notes',
- },
- addPayPalMePage: {
- enterYourUsernameToGetPaidViaPayPal: 'Get paid back via PayPal.',
- payPalMe: 'PayPal.me/',
- yourPayPalUsername: 'Your PayPal username',
- addPayPalAccount: 'Add PayPal account',
- growlMessageOnSave: 'Your PayPal username was successfully added',
- updatePaypalAccount: 'Save PayPal account',
- growlMessageOnUpdate: 'Your PayPal username was successfully saved',
- formatError: 'Invalid PayPal.me username',
- checkListOf: 'Check the list of ',
- supportedCurrencies: 'supported currencies',
+ myNote: 'My note',
},
addDebitCardPage: {
addADebitCard: 'Add a debit card',
@@ -797,7 +800,6 @@ export default {
setDefaultSuccess: 'Default payment method set!',
deleteAccount: 'Delete account',
deleteConfirmation: 'Are you sure that you want to delete this account?',
- deletePayPalSuccess: 'PayPal.me successfully deleted',
error: {
notOwnerOfBankAccount: 'There was an error setting this bank account as your default payment method.',
invalidBankAccount: 'This bank account is temporarily suspended.',
@@ -904,6 +906,7 @@ export default {
validateCodeForm: {
magicCodeNotReceived: "Didn't receive a magic code?",
enterAuthenticatorCode: 'Please enter your authenticator code',
+ enterRecoveryCode: 'Please enter your recovery code',
requiredWhen2FAEnabled: 'Required when 2FA is enabled',
requestNewCode: 'Request a new code in ',
requestNewCodeAfterErrorOccurred: 'Request a new code',
@@ -1316,6 +1319,7 @@ export default {
memberNotFound: 'Member not found. To invite a new member to the workspace, please use the Invite button above.',
notAuthorized: `You do not have access to this page. Are you trying to join the workspace? Please reach out to the owner of this workspace so they can add you as a member! Something else? Reach out to ${CONST.EMAIL.CONCIERGE}`,
goToRoom: ({roomName}: GoToRoomParams) => `Go to ${roomName} room`,
+ workspaceAvatar: 'Workspace avatar',
},
emptyWorkspace: {
title: 'Create a new workspace',
@@ -1524,7 +1528,7 @@ export default {
completed: 'Completed',
messages: {
completed: 'completed task',
- canceled: 'canceled task',
+ canceled: 'deleted task',
reopened: 'reopened task',
error: 'You do not have the permission to do the requested action.',
},
@@ -1696,6 +1700,7 @@ export default {
parentReportAction: {
deletedMessage: '[Deleted message]',
deletedRequest: '[Deleted request]',
+ deletedTask: '[Deleted task]',
hiddenMessage: '[Hidden message]',
},
threads: {
diff --git a/src/languages/es.ts b/src/languages/es.ts
index d83104ff85e0..a68f33a33730 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -25,7 +25,6 @@ import type {
ReportArchiveReasonsPolicyDeletedParams,
RequestCountParams,
SettleExpensifyCardParams,
- SettlePaypalMeParams,
RequestAmountParams,
SplitAmountParams,
AmountEachParams,
@@ -37,7 +36,6 @@ import type {
WaitingOnBankAccountParams,
SettledAfterAddedBankAccountParams,
PaidElsewhereWithAmountParams,
- PaidUsingPaypalWithAmountParams,
PaidWithExpensifyWithAmountParams,
ThreadRequestReportNameParams,
ThreadSentMoneyReportNameParams,
@@ -71,6 +69,8 @@ import type {
SetTheRequestParams,
UpdatedTheRequestParams,
RemovedTheRequestParams,
+ FormattedMaxLengthParams,
+ RequestedAmountMessageParams,
TagSelectionParams,
EnglishTranslation,
} from './types';
@@ -196,7 +196,6 @@ export default {
done: 'Listo',
more: 'Más',
debitCard: 'Tarjeta de débito',
- payPalMe: 'PayPal.me',
bankAccount: 'Cuenta bancaria',
join: 'Unirse',
decline: 'Rechazar',
@@ -234,6 +233,7 @@ export default {
showMore: 'Mostrar más',
merchant: 'Comerciante',
category: 'Categoría',
+ billable: 'Facturable',
tag: 'Etiqueta',
receipt: 'Recibo',
replace: 'Sustituir',
@@ -244,6 +244,7 @@ export default {
kilometers: 'kilómetros',
recent: 'Reciente',
all: 'Todo',
+ tbd: 'Por determinar',
},
anonymousReportFooter: {
logoTagline: 'Únete a la discusión.',
@@ -272,6 +273,7 @@ export default {
composer: {
noExtensionFoundForMimeType: 'No se encontró una extension para este tipo de contenido',
problemGettingImageYouPasted: 'Ha ocurrido un problema al obtener la imagen que has pegado',
+ commentExceededMaxLength: ({formattedMaxLength}: FormattedMaxLengthParams) => `El comentario debe tener máximo ${formattedMaxLength} caracteres.`,
},
baseUpdateAppModal: {
updateApp: 'Actualizar app',
@@ -505,11 +507,10 @@ export default {
deleteConfirmation: '¿Estás seguro de que quieres eliminar este pedido?',
settledExpensify: 'Pagado',
settledElsewhere: 'Pagado de otra forma',
- settledPaypalMe: 'Pagado con PayPal.me',
settleExpensify: ({formattedAmount}: SettleExpensifyCardParams) => `Pagar ${formattedAmount} con Expensify`,
payElsewhere: 'Pagar de otra forma',
- settlePaypalMe: ({formattedAmount}: SettlePaypalMeParams) => `Pagar ${formattedAmount} con PayPal.me`,
requestAmount: ({amount}: RequestAmountParams) => `solicitar ${amount}`,
+ requestedAmount: ({formattedAmount, comment}: RequestedAmountMessageParams) => `solicité ${formattedAmount}${comment ? ` para ${comment}` : ''}`,
splitAmount: ({amount}: SplitAmountParams) => `dividir ${amount}`,
amountEach: ({amount}: AmountEachParams) => `${amount} cada uno`,
payerOwesAmount: ({payer, amount}: PayerOwesAmountParams) => `${payer} debe ${amount}`,
@@ -521,9 +522,8 @@ export default {
waitingOnBankAccount: ({submitterDisplayName}: WaitingOnBankAccountParams) => `inicio el pago, pero no se procesará hasta que ${submitterDisplayName} añada una cuenta bancaria`,
settledAfterAddedBankAccount: ({submitterDisplayName, amount}: SettledAfterAddedBankAccountParams) =>
`${submitterDisplayName} añadió una cuenta bancaria. El pago de ${amount} se ha realizado.`,
- paidElsewhereWithAmount: ({amount}: PaidElsewhereWithAmountParams) => `pagó ${amount} de otra forma`,
- paidUsingPaypalWithAmount: ({amount}: PaidUsingPaypalWithAmountParams) => `pagó ${amount} con PayPal.me`,
- paidWithExpensifyWithAmount: ({amount}: PaidWithExpensifyWithAmountParams) => `pagó ${amount} con Expensify`,
+ paidElsewhereWithAmount: ({payer, amount}: PaidElsewhereWithAmountParams) => `${payer} pagó ${amount} de otra forma`,
+ paidWithExpensifyWithAmount: ({payer, amount}: PaidWithExpensifyWithAmountParams) => `${payer} pagó ${amount} con Expensify`,
noReimbursableExpenses: 'El importe de este informe no es válido',
pendingConversionMessage: 'El total se actualizará cuando estés online',
changedTheRequest: 'cambió la solicitud',
@@ -536,6 +536,7 @@ export default {
threadSentMoneyReportName: ({formattedAmount, comment}: ThreadSentMoneyReportNameParams) => `${formattedAmount} enviado${comment ? ` para ${comment}` : ''}`,
tagSelection: ({tagName}: TagSelectionParams) => `Seleccione una ${tagName} para organizar mejor tu dinero`,
error: {
+ invalidAmount: 'Por favor ingresa un monto válido antes de continuar.',
invalidSplit: 'La suma de las partes no equivale al monto total',
other: 'Error inesperado, por favor inténtalo más tarde',
genericCreateFailureMessage: 'Error inesperado solicitando dinero, Por favor, inténtalo más tarde',
@@ -561,6 +562,8 @@ export default {
uploadPhoto: 'Subir foto',
removePhoto: 'Eliminar foto',
editImage: 'Editar foto',
+ viewPhoto: 'Ver foto',
+ imageUploadFailed: 'Error al cargar la imagen',
deleteWorkspaceError: 'Lo sentimos, hubo un problema eliminando el avatar de su espacio de trabajo.',
sizeExceeded: ({maxUploadSizeInMB}: SizeExceededParams) => `La imagen supera el tamaño máximo de ${maxUploadSizeInMB}MB.`,
resolutionConstraints: ({minHeightInPx, minWidthInPx, maxHeightInPx, maxWidthInPx}: ResolutionConstraintsParams) =>
@@ -580,6 +583,7 @@ export default {
online: 'En línea',
offline: 'Desconectado',
syncing: 'Sincronizando',
+ profileAvatar: 'Perfil avatar',
},
loungeAccessPage: {
loungeAccess: 'Acceso a la sala vip',
@@ -723,6 +727,7 @@ export default {
keepCodesSafe: '¡Guarda los códigos de recuperación en un lugar seguro!',
codesLoseAccess:
'Si pierdes el acceso a tu aplicación de autenticación y no tienes estos códigos, perderás el acceso a tu cuenta. \n\nNota: Configurar la autenticación de dos factores cerrará la sesión de todas las demás sesiones activas.',
+ errorStepCodes: 'Copia o descarga los códigos antes de continuar.',
stepVerify: 'Verificar',
scanCode: 'Escanea el código QR usando tu',
authenticatorApp: 'aplicación de autenticación',
@@ -734,6 +739,15 @@ export default {
copy: 'Copiar',
disable: 'Deshabilitar',
},
+ recoveryCodeForm: {
+ error: {
+ pleaseFillRecoveryCode: 'Por favor, introduce tu código de recuperación',
+ incorrectRecoveryCode: 'Código de recuperación incorrecto. Por favor, inténtalo de nuevo',
+ },
+ useRecoveryCode: 'Usar código de recuperación',
+ recoveryCode: 'Código de recuperación',
+ use2fa: 'Usar autenticación de dos factores',
+ },
twoFactorAuthForm: {
error: {
pleaseFillTwoFactorAuth: 'Por favor, introduce tu código de autenticación de dos factores',
@@ -750,18 +764,7 @@ export default {
sharedNoteMessage: 'Guarda notas sobre este chat aquí. Los empleados de Expensify y otros usuarios del dominio team.expensify.com pueden ver estas notas.',
notesUnavailable: 'No se han encontrado notas para el usuario',
composerLabel: 'Notas',
- },
- addPayPalMePage: {
- enterYourUsernameToGetPaidViaPayPal: 'Recibe pagos vía PayPal.',
- payPalMe: 'PayPal.me/',
- yourPayPalUsername: 'Tu usuario de PayPal',
- addPayPalAccount: 'Añadir cuenta de PayPal',
- growlMessageOnSave: 'Tu nombre de usuario de PayPal se añadió correctamente',
- updatePaypalAccount: 'Guardar cuenta PayPal',
- growlMessageOnUpdate: 'Su nombre de usuario de PayPal se guardó con éxito',
- formatError: 'Usuario PayPal.me no válido',
- checkListOf: 'Consulta la lista de ',
- supportedCurrencies: 'monedas admitidas',
+ myNote: 'Mi notas',
},
addDebitCardPage: {
addADebitCard: 'Añadir una tarjeta de débito',
@@ -792,7 +795,6 @@ export default {
setDefaultSuccess: 'Método de pago configurado',
deleteAccount: 'Eliminar cuenta',
deleteConfirmation: '¿Estás seguro de que quieres eliminar esta cuenta?',
- deletePayPalSuccess: 'PayPal.me eliminada correctamente',
error: {
notOwnerOfBankAccount: 'Ha ocurrido un error al establecer esta cuenta bancaria como método de pago predeterminado.',
invalidBankAccount: 'Esta cuenta bancaria está temporalmente suspendida.',
@@ -900,6 +902,7 @@ export default {
validateCodeForm: {
magicCodeNotReceived: '¿No recibiste un código mágico?',
enterAuthenticatorCode: 'Por favor, introduce el código de autenticador',
+ enterRecoveryCode: 'Por favor, introduce tu código de recuperación',
requiredWhen2FAEnabled: 'Obligatorio cuando A2F está habilitado',
requestNewCode: 'Pedir un código nuevo en ',
requestNewCodeAfterErrorOccurred: 'Solicitar un nuevo código',
@@ -1335,6 +1338,7 @@ export default {
memberNotFound: 'Miembro no encontrado. Para invitar a un nuevo miembro al espacio de trabajo, por favor, utiliza el botón Invitar que está arriba.',
notAuthorized: `No tienes acceso a esta página. ¿Estás tratando de unirte al espacio de trabajo? Comunícate con el propietario de este espacio de trabajo para que pueda añadirte como miembro. ¿Necesitas algo más? Comunícate con ${CONST.EMAIL.CONCIERGE}`,
goToRoom: ({roomName}: GoToRoomParams) => `Ir a la sala ${roomName}`,
+ workspaceAvatar: 'Espacio de trabajo avatar',
},
emptyWorkspace: {
title: 'Crear un nuevo espacio de trabajo',
@@ -1546,7 +1550,7 @@ export default {
completed: 'Completada',
messages: {
completed: 'tarea completada',
- canceled: 'tarea cancelada',
+ canceled: 'tarea eliminado',
reopened: 'tarea reabrir',
error: 'No tiene permiso para realizar la acción solicitada.',
},
@@ -2178,6 +2182,7 @@ export default {
parentReportAction: {
deletedMessage: '[Mensaje eliminado]',
deletedRequest: '[Pedido eliminado]',
+ deletedTask: '[Tarea eliminado]',
hiddenMessage: '[Mensaje oculto]',
},
threads: {
diff --git a/src/languages/types.ts b/src/languages/types.ts
index 565b5933b989..70bf2e4cae3d 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -100,10 +100,10 @@ type SettleExpensifyCardParams = {
formattedAmount: string;
};
-type SettlePaypalMeParams = {formattedAmount: string};
-
type RequestAmountParams = {amount: number};
+type RequestedAmountMessageParams = {formattedAmount: string; comment: string};
+
type SplitAmountParams = {amount: number};
type AmountEachParams = {amount: number};
@@ -124,11 +124,9 @@ type WaitingOnBankAccountParams = {submitterDisplayName: string};
type SettledAfterAddedBankAccountParams = {submitterDisplayName: string; amount: string};
-type PaidElsewhereWithAmountParams = {amount: string};
+type PaidElsewhereWithAmountParams = {payer: string; amount: string};
-type PaidUsingPaypalWithAmountParams = {amount: string};
-
-type PaidWithExpensifyWithAmountParams = {amount: string};
+type PaidWithExpensifyWithAmountParams = {payer: string; amount: string};
type ThreadRequestReportNameParams = {formattedAmount: string; comment: string};
@@ -192,6 +190,8 @@ type RemovedTheRequestParams = {valueName: string; oldValueToDisplay: string};
type UpdatedTheRequestParams = {valueName: string; newValueToDisplay: string; oldValueToDisplay: string};
+type FormattedMaxLengthParams = {formattedMaxLength: string};
+
type TagSelectionParams = {tagName: string};
/* Translation Object types */
@@ -260,8 +260,8 @@ export type {
ReportArchiveReasonsPolicyDeletedParams,
RequestCountParams,
SettleExpensifyCardParams,
- SettlePaypalMeParams,
RequestAmountParams,
+ RequestedAmountMessageParams,
SplitAmountParams,
AmountEachParams,
PayerOwesAmountParams,
@@ -273,7 +273,6 @@ export type {
WaitingOnBankAccountParams,
SettledAfterAddedBankAccountParams,
PaidElsewhereWithAmountParams,
- PaidUsingPaypalWithAmountParams,
PaidWithExpensifyWithAmountParams,
ThreadRequestReportNameParams,
ThreadSentMoneyReportNameParams,
@@ -306,5 +305,6 @@ export type {
SetTheRequestParams,
UpdatedTheRequestParams,
RemovedTheRequestParams,
+ FormattedMaxLengthParams,
TagSelectionParams,
};
diff --git a/src/libs/AppStateMonitor/index.js b/src/libs/AppStateMonitor/index.ts
similarity index 71%
rename from src/libs/AppStateMonitor/index.js
rename to src/libs/AppStateMonitor/index.ts
index 12370382919e..5c206579944d 100644
--- a/src/libs/AppStateMonitor/index.js
+++ b/src/libs/AppStateMonitor/index.ts
@@ -1,20 +1,15 @@
-import {AppState} from 'react-native';
+import {AppState, AppStateStatus} from 'react-native';
import CONST from '../../CONST';
import shouldReportActivity from './shouldReportActivity';
-let appState = CONST.APP_STATE.ACTIVE;
+let appState: AppStateStatus = CONST.APP_STATE.ACTIVE;
/**
* Listener that will only fire the callback when the user has become active.
- *
- * @param {Function} callback
- * @returns {Function} to unsubscribe
+ * @returns callback to unsubscribe
*/
-function addBecameActiveListener(callback) {
- /**
- * @param {String} state
- */
- function appStateChangeCallback(state) {
+function addBecameActiveListener(callback: () => void): () => void {
+ function appStateChangeCallback(state: AppStateStatus) {
if (shouldReportActivity && (appState === CONST.APP_STATE.INACTIVE || appState === CONST.APP_STATE.BACKGROUND) && state === CONST.APP_STATE.ACTIVE) {
callback();
}
diff --git a/src/libs/AppStateMonitor/shouldReportActivity/index.native.js b/src/libs/AppStateMonitor/shouldReportActivity/index.native.js
deleted file mode 100644
index ff3177babdde..000000000000
--- a/src/libs/AppStateMonitor/shouldReportActivity/index.native.js
+++ /dev/null
@@ -1 +0,0 @@
-export default true;
diff --git a/src/libs/AppStateMonitor/shouldReportActivity/index.native.ts b/src/libs/AppStateMonitor/shouldReportActivity/index.native.ts
new file mode 100644
index 000000000000..0e5fdb57a597
--- /dev/null
+++ b/src/libs/AppStateMonitor/shouldReportActivity/index.native.ts
@@ -0,0 +1,5 @@
+import ShouldReportActivity from './types';
+
+const shouldReportActivity: ShouldReportActivity = true;
+
+export default shouldReportActivity;
diff --git a/src/libs/AppStateMonitor/shouldReportActivity/index.js b/src/libs/AppStateMonitor/shouldReportActivity/index.ts
similarity index 70%
rename from src/libs/AppStateMonitor/shouldReportActivity/index.js
rename to src/libs/AppStateMonitor/shouldReportActivity/index.ts
index 05939ab7eb8d..db326345714e 100644
--- a/src/libs/AppStateMonitor/shouldReportActivity/index.js
+++ b/src/libs/AppStateMonitor/shouldReportActivity/index.ts
@@ -1,4 +1,8 @@
+import ShouldReportActivity from './types';
+
// We only need to report when the app becomes active on native since web maintains most of it's network functions while
// in the "background" and the concept is not quite the same on mobile. We avoid setting this to true for web since
// the event would fire much more frequently than it does on native causing performance issues.
-export default false;
+const shouldReportActivity: ShouldReportActivity = false;
+
+export default shouldReportActivity;
diff --git a/src/libs/AppStateMonitor/shouldReportActivity/types.ts b/src/libs/AppStateMonitor/shouldReportActivity/types.ts
new file mode 100644
index 000000000000..2341c0d5cbf1
--- /dev/null
+++ b/src/libs/AppStateMonitor/shouldReportActivity/types.ts
@@ -0,0 +1,3 @@
+type ShouldReportActivity = boolean;
+
+export default ShouldReportActivity;
diff --git a/src/libs/BootSplash/index.js b/src/libs/BootSplash/index.js
index ff7ab5562b1f..c169f380a8eb 100644
--- a/src/libs/BootSplash/index.js
+++ b/src/libs/BootSplash/index.js
@@ -9,10 +9,14 @@ function hide() {
return document.fonts.ready.then(() => {
const splash = document.getElementById('splash');
- if (splash) splash.style.opacity = 0;
+ if (splash) {
+ splash.style.opacity = 0;
+ }
return resolveAfter(250).then(() => {
- if (!splash || !splash.parentNode) return;
+ if (!splash || !splash.parentNode) {
+ return;
+ }
splash.parentNode.removeChild(splash);
});
});
diff --git a/src/libs/ComposerUtils/getDraftComment.js b/src/libs/ComposerUtils/getDraftComment.js
index ddcb966bb2a7..854df1ac65ee 100644
--- a/src/libs/ComposerUtils/getDraftComment.js
+++ b/src/libs/ComposerUtils/getDraftComment.js
@@ -5,7 +5,9 @@ const draftCommentMap = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT,
callback: (value, key) => {
- if (!key) return;
+ if (!key) {
+ return;
+ }
const reportID = key.replace(ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT, '');
draftCommentMap[reportID] = value;
diff --git a/src/libs/CurrencyUtils.js b/src/libs/CurrencyUtils.js
index 6cbb0db7661b..5cf0b22ef337 100644
--- a/src/libs/CurrencyUtils.js
+++ b/src/libs/CurrencyUtils.js
@@ -128,4 +128,25 @@ function convertToDisplayString(amountInCents, currency = CONST.CURRENCY.USD) {
});
}
-export {getCurrencyDecimals, getCurrencyUnit, getLocalizedCurrencySymbol, getCurrencySymbol, isCurrencySymbolLTR, convertToBackendAmount, convertToFrontendAmount, convertToDisplayString};
+/**
+ * Checks if passed currency code is a valid currency based on currency list
+ *
+ * @param {String} currencyCode
+ * @returns {Boolean}
+ */
+function isValidCurrencyCode(currencyCode) {
+ const currency = lodashGet(currencyList, currencyCode);
+ return Boolean(currency);
+}
+
+export {
+ getCurrencyDecimals,
+ getCurrencyUnit,
+ getLocalizedCurrencySymbol,
+ getCurrencySymbol,
+ isCurrencySymbolLTR,
+ convertToBackendAmount,
+ convertToFrontendAmount,
+ convertToDisplayString,
+ isValidCurrencyCode,
+};
diff --git a/src/libs/DateUtils.js b/src/libs/DateUtils.js
index b33a1b1b2a73..70c4277bdb5e 100644
--- a/src/libs/DateUtils.js
+++ b/src/libs/DateUtils.js
@@ -298,7 +298,9 @@ function getDateStringFromISOTimestamp(isoTimestamp) {
* @returns {String}
*/
function getStatusUntilDate(inputDate) {
- if (!inputDate) return '';
+ if (!inputDate) {
+ return '';
+ }
const {translateLocal} = Localize;
const input = new Date(inputDate);
diff --git a/src/libs/DistanceRequestUtils.js b/src/libs/DistanceRequestUtils.js
index 51e37530465d..34fa14163835 100644
--- a/src/libs/DistanceRequestUtils.js
+++ b/src/libs/DistanceRequestUtils.js
@@ -64,21 +64,34 @@ function convertDistanceUnit(distanceInMeters, unit) {
*
* @param {Number} distanceInMeters Distance traveled
* @param {'mi' | 'km'} unit Unit that should be used to display the distance
+ * @returns {String} The distance in requested units, rounded to 2 decimals
+ */
+const getRoundedDistanceInUnits = (distanceInMeters, unit) => {
+ const convertedDistance = convertDistanceUnit(distanceInMeters, unit);
+ return convertedDistance.toFixed(2);
+};
+
+/**
+ *
+ * @param {boolean} hasRoute Whether the route exists for the distance request
+ * @param {Number} distanceInMeters Distance traveled
+ * @param {'mi' | 'km'} unit Unit that should be used to display the distance
* @param {Number} rate Expensable amount allowed per unit
* @param {String} currency The currency associated with the rate
* @param {Function} translate Translate function
- * @returns {String} A string that describes the distance travled and the rate used for expense calculation
+ * @returns {String} A string that describes the distance traveled and the rate used for expense calculation
*/
-const getDistanceMerchant = (distanceInMeters, unit, rate, currency, translate) => {
- const convertedDistance = convertDistanceUnit(distanceInMeters, unit);
+const getDistanceMerchant = (hasRoute, distanceInMeters, unit, rate, currency, translate) => {
+ const distanceInUnits = hasRoute ? getRoundedDistanceInUnits(distanceInMeters, unit) : translate('common.tbd');
+
const distanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.miles') : translate('common.kilometers');
const singularDistanceUnit = unit === CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES ? translate('common.mile') : translate('common.kilometer');
- const roundedDistance = convertedDistance.toFixed(2);
- const unitString = roundedDistance === 1 ? singularDistanceUnit : distanceUnit;
+ const unitString = distanceInUnits === 1 ? singularDistanceUnit : distanceUnit;
+
const ratePerUnit = rate * 0.01;
const currencySymbol = CurrencyUtils.getCurrencySymbol(currency) || `${currency} `;
- return `${roundedDistance} ${unitString} @ ${currencySymbol}${ratePerUnit} / ${singularDistanceUnit}`;
+ return `${distanceInUnits} ${unitString} @ ${currencySymbol}${ratePerUnit} / ${singularDistanceUnit}`;
};
/**
diff --git a/src/libs/DomUtils/index.js b/src/libs/DomUtils/index.js
deleted file mode 100644
index ad636c6167fb..000000000000
--- a/src/libs/DomUtils/index.js
+++ /dev/null
@@ -1,12 +0,0 @@
-function blurActiveElement() {
- document.activeElement.blur();
-}
-
-function getActiveElement() {
- return document.activeElement;
-}
-
-export default {
- blurActiveElement,
- getActiveElement,
-};
diff --git a/src/libs/DomUtils/index.native.js b/src/libs/DomUtils/index.native.js
deleted file mode 100644
index 1d3ef14c954d..000000000000
--- a/src/libs/DomUtils/index.native.js
+++ /dev/null
@@ -1,10 +0,0 @@
-function blurActiveElement() {}
-
-function getActiveElement() {
- return undefined;
-}
-
-export default {
- blurActiveElement,
- getActiveElement,
-};
diff --git a/src/libs/DomUtils/index.native.ts b/src/libs/DomUtils/index.native.ts
new file mode 100644
index 000000000000..d3774baec208
--- /dev/null
+++ b/src/libs/DomUtils/index.native.ts
@@ -0,0 +1,10 @@
+import {BlurActiveElement, GetActiveElement} from './types';
+
+const blurActiveElement: BlurActiveElement = () => {};
+
+const getActiveElement: GetActiveElement = () => null;
+
+export default {
+ blurActiveElement,
+ getActiveElement,
+};
diff --git a/src/libs/DomUtils/index.ts b/src/libs/DomUtils/index.ts
new file mode 100644
index 000000000000..784a01bd7885
--- /dev/null
+++ b/src/libs/DomUtils/index.ts
@@ -0,0 +1,18 @@
+import {BlurActiveElement, GetActiveElement} from './types';
+
+const blurActiveElement: BlurActiveElement = () => {
+ const activeElement = document.activeElement as HTMLElement;
+
+ if (!activeElement?.blur) {
+ return;
+ }
+
+ activeElement.blur();
+};
+
+const getActiveElement: GetActiveElement = () => document.activeElement;
+
+export default {
+ blurActiveElement,
+ getActiveElement,
+};
diff --git a/src/libs/DomUtils/types.ts b/src/libs/DomUtils/types.ts
new file mode 100644
index 000000000000..8be7b3cddae5
--- /dev/null
+++ b/src/libs/DomUtils/types.ts
@@ -0,0 +1,4 @@
+type BlurActiveElement = () => void;
+type GetActiveElement = () => Element | null;
+
+export type {BlurActiveElement, GetActiveElement};
diff --git a/src/libs/E2E/apiMocks/openApp.js b/src/libs/E2E/apiMocks/openApp.js
index 745c1952f07d..d50f4462cfd9 100644
--- a/src/libs/E2E/apiMocks/openApp.js
+++ b/src/libs/E2E/apiMocks/openApp.js
@@ -1094,7 +1094,6 @@ export default () => ({
},
firstName: '',
lastName: '',
- payPalMeAddress: 'qwerty',
phoneNumber: '',
validated: true,
},
@@ -1110,7 +1109,6 @@ export default () => ({
},
firstName: '"Chat N',
lastName: 'Laz"',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1126,7 +1124,6 @@ export default () => ({
},
firstName: '',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1142,7 +1139,6 @@ export default () => ({
},
firstName: '123',
lastName: 'Ios',
- payPalMeAddress: 'Wwerty',
phoneNumber: '',
validated: true,
},
@@ -1158,7 +1154,6 @@ export default () => ({
},
firstName: 'Qqq',
lastName: 'Qqq',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1174,7 +1169,6 @@ export default () => ({
},
firstName: 'Main',
lastName: 'Ios🏴ios',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1190,7 +1184,6 @@ export default () => ({
},
firstName: '0604',
lastName: 'Lsn',
- payPalMeAddress: '12345',
phoneNumber: '',
validated: true,
},
@@ -1206,7 +1199,6 @@ export default () => ({
},
firstName: '07 04 0704',
lastName: 'Lsn lsn',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1222,7 +1214,6 @@ export default () => ({
},
firstName: 'Katya',
lastName: 'Becciv',
- payPalMeAddress: 'testing',
phoneNumber: '',
validated: true,
},
@@ -1238,7 +1229,6 @@ export default () => ({
},
firstName: 'Katie',
lastName: 'Becciv',
- payPalMeAddress: 'kbecciv',
phoneNumber: '',
validated: true,
},
@@ -1254,7 +1244,6 @@ export default () => ({
},
firstName: '11',
lastName: '11',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1270,7 +1259,6 @@ export default () => ({
},
firstName: '"First"',
lastName: '',
- payPalMeAddress: '444555',
phoneNumber: '',
validated: true,
},
@@ -1286,7 +1274,6 @@ export default () => ({
},
firstName: 'bernardo',
lastName: 'utest',
- payPalMeAddress: '',
phoneNumber: '',
validated: false,
},
@@ -1302,7 +1289,6 @@ export default () => ({
},
firstName: 'Chat',
lastName: 'HT',
- payPalMeAddress: '111',
phoneNumber: '',
validated: true,
},
@@ -1318,7 +1304,6 @@ export default () => ({
},
firstName: '',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1334,7 +1319,6 @@ export default () => ({
},
firstName: '',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1350,7 +1334,6 @@ export default () => ({
},
firstName: '',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
localCurrencyCode: 'USD',
@@ -1367,7 +1350,6 @@ export default () => ({
},
firstName: '',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1383,7 +1365,6 @@ export default () => ({
},
firstName: '',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1399,7 +1380,6 @@ export default () => ({
},
firstName: 'Applause',
lastName: 'Main Account',
- payPalMeAddress: 'ss',
phoneNumber: '',
validated: true,
},
@@ -1415,7 +1395,6 @@ export default () => ({
},
firstName: 'Christoph',
lastName: 'Pader',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1431,7 +1410,6 @@ export default () => ({
},
firstName: 'Concierge',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1447,7 +1425,6 @@ export default () => ({
},
firstName: 'Chat S',
lastName: '',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -1463,7 +1440,6 @@ export default () => ({
},
firstName: 'Tayla',
lastName: 'Simmons',
- payPalMeAddress: '',
phoneNumber: '',
validated: true,
},
@@ -2162,7 +2138,6 @@ export default () => ({
cachedTotal: '($1,473.11)',
total: 147311,
stateNum: 1,
- submitterPayPalMeAddress: '',
hasOutstandingIOU: true,
},
report_4249286573496381: {
@@ -2175,7 +2150,6 @@ export default () => ({
cachedTotal: '($212.78)',
total: 21278,
stateNum: 1,
- submitterPayPalMeAddress: '',
hasOutstandingIOU: true,
},
},
diff --git a/src/libs/EmojiTrie.js b/src/libs/EmojiTrie.ts
similarity index 53%
rename from src/libs/EmojiTrie.js
rename to src/libs/EmojiTrie.ts
index 00e5fc1388e1..d0a53acf29c9 100644
--- a/src/libs/EmojiTrie.js
+++ b/src/libs/EmojiTrie.ts
@@ -1,29 +1,61 @@
-import _ from 'underscore';
+import React from 'react';
+import {SvgProps} from 'react-native-svg';
import emojis, {localeEmojis} from '../../assets/emojis';
import Trie from './Trie';
import Timing from './actions/Timing';
import CONST from '../CONST';
+type Emoji = {
+ code: string;
+ header?: boolean;
+ icon?: React.FC;
+ name?: string;
+ types?: string[];
+};
+
+type LocalizedEmoji = {
+ name?: string;
+ keywords: string[];
+};
+
+type LocalizedEmojis = Record;
+
+type Suggestion = {
+ code: string;
+ types?: string[];
+ name?: string;
+};
+
+type EmojiMetaData = {
+ suggestions?: Suggestion[];
+};
+
Timing.start(CONST.TIMING.TRIE_INITIALIZATION);
-const supportedLanguages = [CONST.LOCALES.DEFAULT, CONST.LOCALES.ES];
+const supportedLanguages = [CONST.LOCALES.DEFAULT, CONST.LOCALES.ES] as const;
+
+type SupportedLanguage = (typeof supportedLanguages)[number];
+
+type EmojiTrie = {
+ [key in SupportedLanguage]?: Trie;
+};
/**
*
- * @param {Trie} trie The Trie object.
- * @param {Array} keywords An array containing the keywords.
- * @param {Object} item An object containing the properties of the emoji.
- * @param {String} name The localized name of the emoji.
- * @param {Boolean} shouldPrependKeyword Prepend the keyword (instead of append) to the suggestions
+ * @param trie The Trie object.
+ * @param keywords An array containing the keywords.
+ * @param item An object containing the properties of the emoji.
+ * @param name The localized name of the emoji.
+ * @param shouldPrependKeyword Prepend the keyword (instead of append) to the suggestions
*/
-function addKeywordsToTrie(trie, keywords, item, name, shouldPrependKeyword = false) {
- _.forEach(keywords, (keyword) => {
+function addKeywordsToTrie(trie: Trie, keywords: string[], item: Emoji, name: string, shouldPrependKeyword = false) {
+ keywords.forEach((keyword) => {
const keywordNode = trie.search(keyword);
if (!keywordNode) {
trie.add(keyword, {suggestions: [{code: item.code, types: item.types, name}]});
} else {
const suggestion = {code: item.code, types: item.types, name};
- const suggestions = shouldPrependKeyword ? [suggestion, ...keywordNode.metaData.suggestions] : [...keywordNode.metaData.suggestions, suggestion];
+ const suggestions = shouldPrependKeyword ? [suggestion, ...(keywordNode.metaData.suggestions ?? [])] : [...(keywordNode.metaData.suggestions ?? []), suggestion];
trie.update(keyword, {
...keywordNode.metaData,
suggestions,
@@ -35,26 +67,27 @@ function addKeywordsToTrie(trie, keywords, item, name, shouldPrependKeyword = fa
/**
* Allows searching based on parts of the name. This turns 'white_large_square' into ['white_large_square', 'large_square', 'square'].
*
- * @param {String} name The emoji name
- * @returns {Array} An array containing the name parts
+ * @param name The emoji name
+ * @returns An array containing the name parts
*/
-function getNameParts(name) {
+function getNameParts(name: string): string[] {
const nameSplit = name.split('_');
- return _.map(nameSplit, (_namePart, index) => nameSplit.slice(index).join('_'));
+ return nameSplit.map((namePart, index) => nameSplit.slice(index).join('_'));
}
-function createTrie(lang = CONST.LOCALES.DEFAULT) {
+function createTrie(lang: SupportedLanguage = CONST.LOCALES.DEFAULT): Trie {
const trie = new Trie();
- const langEmojis = localeEmojis[lang];
+ const langEmojis: LocalizedEmojis = localeEmojis[lang];
+ const defaultLangEmojis: LocalizedEmojis = localeEmojis[CONST.LOCALES.DEFAULT];
const isDefaultLocale = lang === CONST.LOCALES.DEFAULT;
- _.forEach(emojis, (item) => {
- if (item.header) {
+ emojis.forEach((item: Emoji) => {
+ if (!item.name) {
return;
}
const englishName = item.name;
- const localeName = _.get(langEmojis, [item.code, 'name'], englishName);
+ const localeName = langEmojis?.[item.code]?.name ?? englishName;
const node = trie.search(localeName);
if (!node) {
@@ -67,7 +100,7 @@ function createTrie(lang = CONST.LOCALES.DEFAULT) {
addKeywordsToTrie(trie, nameParts, item, localeName);
// Add keywords for both the locale language and English to enable users to search using either language.
- const keywords = _.get(langEmojis, [item.code, 'keywords'], []).concat(isDefaultLocale ? [] : _.get(localeEmojis, [CONST.LOCALES.DEFAULT, item.code, 'keywords'], []));
+ const keywords = (langEmojis?.[item.code]?.keywords ?? []).concat(isDefaultLocale ? [] : defaultLangEmojis?.[item.code]?.keywords ?? []);
addKeywordsToTrie(trie, keywords, item, localeName);
/**
@@ -83,7 +116,7 @@ function createTrie(lang = CONST.LOCALES.DEFAULT) {
return trie;
}
-const emojiTrie = _.reduce(supportedLanguages, (prev, cur) => ({...prev, [cur]: createTrie(cur)}), {});
+const emojiTrie: EmojiTrie = supportedLanguages.reduce((prev, cur) => ({...prev, [cur]: createTrie(cur)}), {});
Timing.end(CONST.TIMING.TRIE_INITIALIZATION);
diff --git a/src/libs/FormHelper.js b/src/libs/FormHelper.js
deleted file mode 100644
index feab0f44acea..000000000000
--- a/src/libs/FormHelper.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import lodashUnset from 'lodash/unset';
-import lodashCloneDeep from 'lodash/cloneDeep';
-
-class FormHelper {
- constructor({errorPath, setErrors}) {
- this.errorPath = errorPath;
- this.setErrors = setErrors;
- this.getErrors = this.getErrors.bind(this);
- this.clearError = this.clearError.bind(this);
- this.clearErrors = this.clearErrors.bind(this);
- }
-
- /**
- * @param {Object} props
- * @returns {Object}
- */
- getErrors(props) {
- return lodashGet(props, this.errorPath, {});
- }
-
- /**
- * @param {Object} props
- * @param {String[]} paths
- */
- clearErrors(props, paths) {
- const errors = this.getErrors(props);
- const pathsWithErrors = _.filter(paths, (path) => lodashGet(errors, path, false));
- if (_.size(pathsWithErrors) === 0) {
- // No error found for this path
- return;
- }
-
- // Clear the existing errors
- const newErrors = lodashCloneDeep(errors);
- _.forEach(pathsWithErrors, (path) => lodashUnset(newErrors, path));
- this.setErrors(newErrors);
- }
-
- /**
- * @param {Object} props
- * @param {String} path
- */
- clearError(props, path) {
- this.clearErrors(props, [path]);
- }
-}
-
-export default FormHelper;
diff --git a/src/libs/IOUUtils.js b/src/libs/IOUUtils.ts
similarity index 51%
rename from src/libs/IOUUtils.js
rename to src/libs/IOUUtils.ts
index 2042c6beda05..6f6024506985 100644
--- a/src/libs/IOUUtils.js
+++ b/src/libs/IOUUtils.ts
@@ -1,18 +1,17 @@
-import _ from 'underscore';
import CONST from '../CONST';
import * as TransactionUtils from './TransactionUtils';
import * as CurrencyUtils from './CurrencyUtils';
+import {Report, Transaction} from '../types/onyx';
/**
* Calculates the amount per user given a list of participants
*
- * @param {Number} numberOfParticipants - Number of participants in the chat. It should not include the current user.
- * @param {Number} total - IOU total amount in backend format (cents, no matter the currency)
- * @param {String} currency - This is used to know how many decimal places are valid to use when splitting the total
- * @param {Boolean} isDefaultUser - Whether we are calculating the amount for the current user
- * @returns {Number}
+ * @param numberOfParticipants - Number of participants in the chat. It should not include the current user.
+ * @param total - IOU total amount in backend format (cents, no matter the currency)
+ * @param currency - This is used to know how many decimal places are valid to use when splitting the total
+ * @param isDefaultUser - Whether we are calculating the amount for the current user
*/
-function calculateAmount(numberOfParticipants, total, currency, isDefaultUser = false) {
+function calculateAmount(numberOfParticipants: number, total: number, currency: string, isDefaultUser = false): number {
// Since the backend can maximum store 2 decimal places, any currency with more than 2 decimals
// has to be capped to 2 decimal places
const currencyUnit = Math.min(100, CurrencyUtils.getCurrencyUnit(currency));
@@ -34,35 +33,32 @@ function calculateAmount(numberOfParticipants, total, currency, isDefaultUser =
* For example: if user1 owes user2 $10, then we have: {ownerAccountID: user2, managerID: user1, total: $10 (a positive amount, owed to user2)}
* If user1 requests $17 from user2, then we have: {ownerAccountID: user1, managerID: user2, total: $7 (still a positive amount, but now owed to user1)}
*
- * @param {Object} iouReport
- * @param {Number} actorAccountID
- * @param {Number} amount
- * @param {String} currency
- * @param {String} isDeleting - whether the user is deleting the request
- * @returns {Object}
+ * @param isDeleting - whether the user is deleting the request
*/
-function updateIOUOwnerAndTotal(iouReport, actorAccountID, amount, currency, isDeleting = false) {
+function updateIOUOwnerAndTotal(iouReport: Report, actorAccountID: number, amount: number, currency: string, isDeleting = false): Report {
if (currency !== iouReport.currency) {
return iouReport;
}
// Make a copy so we don't mutate the original object
- const iouReportUpdate = {...iouReport};
+ const iouReportUpdate: Report = {...iouReport};
- if (actorAccountID === iouReport.ownerAccountID) {
- iouReportUpdate.total += isDeleting ? -amount : amount;
- } else {
- iouReportUpdate.total += isDeleting ? amount : -amount;
- }
+ if (iouReportUpdate.total) {
+ if (actorAccountID === iouReport.ownerAccountID) {
+ iouReportUpdate.total += isDeleting ? -amount : amount;
+ } else {
+ iouReportUpdate.total += isDeleting ? amount : -amount;
+ }
- if (iouReportUpdate.total < 0) {
- // The total sign has changed and hence we need to flip the manager and owner of the report.
- iouReportUpdate.ownerAccountID = iouReport.managerID;
- iouReportUpdate.managerID = iouReport.ownerAccountID;
- iouReportUpdate.total = -iouReportUpdate.total;
- }
+ if (iouReportUpdate.total < 0) {
+ // The total sign has changed and hence we need to flip the manager and owner of the report.
+ iouReportUpdate.ownerAccountID = iouReport.managerID;
+ iouReportUpdate.managerID = iouReport.ownerAccountID;
+ iouReportUpdate.total = -iouReportUpdate.total;
+ }
- iouReportUpdate.hasOutstandingIOU = iouReportUpdate.total !== 0;
+ iouReportUpdate.hasOutstandingIOU = iouReportUpdate.total !== 0;
+ }
return iouReportUpdate;
}
@@ -70,23 +66,19 @@ function updateIOUOwnerAndTotal(iouReport, actorAccountID, amount, currency, isD
/**
* Returns whether or not an IOU report contains money requests in a different currency
* that are either created or cancelled offline, and thus haven't been converted to the report's currency yet
- *
- * @param {Object} iouReport
- * @returns {Boolean}
*/
-function isIOUReportPendingCurrencyConversion(iouReport) {
- const reportTransactions = TransactionUtils.getAllReportTransactions(iouReport.reportID);
- const pendingRequestsInDifferentCurrency = _.filter(reportTransactions, (transaction) => transaction.pendingAction && TransactionUtils.getCurrency(transaction) !== iouReport.currency);
+function isIOUReportPendingCurrencyConversion(iouReport: Report): boolean {
+ const reportTransactions: Transaction[] = TransactionUtils.getAllReportTransactions(iouReport.reportID);
+ const pendingRequestsInDifferentCurrency = reportTransactions.filter((transaction) => transaction.pendingAction && TransactionUtils.getCurrency(transaction) !== iouReport.currency);
return pendingRequestsInDifferentCurrency.length > 0;
}
/**
* Checks if the iou type is one of request, send, or split.
- * @param {String} iouType
- * @returns {Boolean}
*/
-function isValidMoneyRequestType(iouType) {
- return [CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT].includes(iouType);
+function isValidMoneyRequestType(iouType: string): boolean {
+ const moneyRequestType: string[] = [CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT];
+ return moneyRequestType.includes(iouType);
}
export {calculateAmount, updateIOUOwnerAndTotal, isIOUReportPendingCurrencyConversion, isValidMoneyRequestType};
diff --git a/src/libs/Log.js b/src/libs/Log.ts
similarity index 70%
rename from src/libs/Log.js
rename to src/libs/Log.ts
index e51fb74aedd5..cf139eec2682 100644
--- a/src/libs/Log.js
+++ b/src/libs/Log.ts
@@ -1,45 +1,43 @@
// Making an exception to this rule here since we don't need an "action" for Log and Log should just be used directly. Creating a Log
// action would likely cause confusion about which one to use. But most other API methods should happen inside an action file.
/* eslint-disable rulesdir/no-api-in-views */
+import {Merge} from 'type-fest';
import Logger from 'expensify-common/lib/Logger';
import getPlatform from './getPlatform';
import pkg from '../../package.json';
import requireParameters from './requireParameters';
import * as Network from './Network';
-let timeout = null;
+let timeout: NodeJS.Timeout;
-/**
- * @param {Object} parameters
- * @param {String} parameters.expensifyCashAppVersion
- * @param {Object[]} parameters.logPacket
- * @returns {Promise}
- */
-function LogCommand(parameters) {
+type LogCommandParameters = {
+ expensifyCashAppVersion: string;
+ logPacket: string;
+};
+
+function LogCommand(parameters: LogCommandParameters): Promise<{requestID: string}> {
const commandName = 'Log';
requireParameters(['logPacket', 'expensifyCashAppVersion'], parameters, commandName);
// Note: We are forcing Log to run since it requires no authToken and should only be queued when we are offline.
// Non-cancellable request: during logout, when requests are cancelled, we don't want to cancel any remaining logs
- return Network.post(commandName, {...parameters, forceNetworkRequest: true, canCancel: false});
+ return Network.post(commandName, {...parameters, forceNetworkRequest: true, canCancel: false}) as Promise<{requestID: string}>;
}
+// eslint-disable-next-line
+type ServerLoggingCallbackOptions = {api_setCookie: boolean; logPacket: string};
+type RequestParams = Merge;
+
/**
* Network interface for logger.
- *
- * @param {Logger} logger
- * @param {Object} params
- * @param {Object} params.parameters
- * @param {String} params.message
- * @return {Promise}
*/
-function serverLoggingCallback(logger, params) {
- const requestParams = params;
+function serverLoggingCallback(logger: Logger, params: ServerLoggingCallbackOptions): Promise<{requestID: string}> {
+ const requestParams = params as RequestParams;
requestParams.shouldProcessImmediately = false;
requestParams.shouldRetry = false;
requestParams.expensifyCashAppVersion = `expensifyCash[${getPlatform()}]${pkg.version}`;
if (requestParams.parameters) {
- requestParams.parameters = JSON.stringify(params.parameters);
+ requestParams.parameters = JSON.stringify(requestParams.parameters);
}
clearTimeout(timeout);
timeout = setTimeout(() => logger.info('Flushing logs older than 10 minutes', true, {}, true), 10 * 60 * 1000);
diff --git a/src/libs/MoneyRequestUtils.js b/src/libs/MoneyRequestUtils.ts
similarity index 53%
rename from src/libs/MoneyRequestUtils.js
rename to src/libs/MoneyRequestUtils.ts
index e60eae0cdfe5..b8a6a3da303f 100644
--- a/src/libs/MoneyRequestUtils.js
+++ b/src/libs/MoneyRequestUtils.ts
@@ -1,47 +1,36 @@
-import lodashGet from 'lodash/get';
-import _ from 'underscore';
+import {ValueOf} from 'type-fest';
import CONST from '../CONST';
/**
* Strip comma from the amount
- *
- * @param {String} amount
- * @returns {String}
*/
-function stripCommaFromAmount(amount) {
+function stripCommaFromAmount(amount: string): string {
return amount.replace(/,/g, '');
}
/**
* Strip spaces from the amount
- *
- * @param {String} amount
- * @returns {String}
*/
-function stripSpacesFromAmount(amount) {
+function stripSpacesFromAmount(amount: string): string {
return amount.replace(/\s+/g, '');
}
/**
* Adds a leading zero to the amount if user entered just the decimal separator
*
- * @param {String} amount - Changed amount from user input
- * @returns {String}
+ * @param amount - Changed amount from user input
*/
-function addLeadingZero(amount) {
+function addLeadingZero(amount: string): string {
return amount === '.' ? '0.' : amount;
}
/**
* Calculate the length of the amount with leading zeroes
- *
- * @param {String} amount
- * @returns {Number}
*/
-function calculateAmountLength(amount) {
+function calculateAmountLength(amount: string): number {
const leadingZeroes = amount.match(/^0+/);
- const leadingZeroesLength = lodashGet(leadingZeroes, '[0].length', 0);
- const absAmount = parseFloat((stripCommaFromAmount(amount) * 100).toFixed(2)).toString();
+ const leadingZeroesLength = leadingZeroes?.[0]?.length ?? 0;
+ const absAmount = parseFloat((Number(stripCommaFromAmount(amount)) * 100).toFixed(2)).toString();
if (/\D/.test(absAmount)) {
return CONST.IOU.AMOUNT_MAX_LENGTH + 1;
@@ -52,11 +41,8 @@ function calculateAmountLength(amount) {
/**
* Check if amount is a decimal up to 3 digits
- *
- * @param {String} amount
- * @returns {Boolean}
*/
-function validateAmount(amount) {
+function validateAmount(amount: string): boolean {
const decimalNumberRegex = new RegExp(/^\d+(,\d+)*(\.\d{0,2})?$/, 'i');
return amount === '' || (decimalNumberRegex.test(amount) && calculateAmountLength(amount) <= CONST.IOU.AMOUNT_MAX_LENGTH);
}
@@ -64,13 +50,10 @@ function validateAmount(amount) {
/**
* Replaces each character by calling `convertFn`. If `convertFn` throws an error, then
* the original character will be preserved.
- *
- * @param {String} text
- * @param {Function} convertFn - `fromLocaleDigit` or `toLocaleDigit`
- * @returns {String}
*/
-function replaceAllDigits(text, convertFn) {
- return _.chain([...text])
+function replaceAllDigits(text: string, convertFn: (char: string) => string): string {
+ return text
+ .split('')
.map((char) => {
try {
return convertFn(char);
@@ -78,19 +61,21 @@ function replaceAllDigits(text, convertFn) {
return char;
}
})
- .join('')
- .value();
+ .join('');
}
/**
* Check if distance request or not
- *
- * @param {String} iouType - `send` | `split` | `request`
- * @param {String} selectedTab - `manual` | `scan` | `distance`
- * @returns {Boolean}
*/
-function isDistanceRequest(iouType, selectedTab) {
+function isDistanceRequest(iouType: ValueOf, selectedTab: ValueOf): boolean {
return iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST && selectedTab === CONST.TAB.DISTANCE;
}
-export {stripCommaFromAmount, stripSpacesFromAmount, addLeadingZero, validateAmount, replaceAllDigits, isDistanceRequest};
+/**
+ * Check if scan request or not
+ */
+function isScanRequest(selectedTab: ValueOf): boolean {
+ return selectedTab === CONST.TAB.SCAN;
+}
+
+export {stripCommaFromAmount, stripSpacesFromAmount, addLeadingZero, validateAmount, replaceAllDigits, isDistanceRequest, isScanRequest};
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index e0197805f09c..16d0e2225007 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -38,6 +38,8 @@ import DemoSetupPage from '../../../pages/DemoSetupPage';
let timezone;
let currentAccountID;
+let isLoadingApp;
+
Onyx.connect({
key: ONYXKEYS.SESSION,
callback: (val) => {
@@ -75,6 +77,13 @@ Onyx.connect({
},
});
+Onyx.connect({
+ key: ONYXKEYS.IS_LOADING_APP,
+ callback: (val) => {
+ isLoadingApp = val;
+ },
+});
+
const RootStack = createCustomStackNavigator();
// We want to delay the re-rendering for components(e.g. ReportActionCompose)
@@ -126,7 +135,13 @@ class AuthScreens extends React.Component {
componentDidMount() {
NetworkConnection.listenForReconnect();
- NetworkConnection.onReconnect(() => App.reconnectApp(this.props.lastUpdateIDAppliedToClient));
+ NetworkConnection.onReconnect(() => {
+ if (isLoadingApp) {
+ App.openApp();
+ } else {
+ App.reconnectApp(this.props.lastUpdateIDAppliedToClient);
+ }
+ });
PusherConnectionManager.init();
Pusher.init({
appKey: CONFIG.PUSHER.APP_KEY,
@@ -182,10 +197,10 @@ class AuthScreens extends React.Component {
chatShortcutConfig.shortcutKey,
() => {
Modal.close(() => {
- if (Navigation.isActiveRoute(ROUTES.NEW_CHAT)) {
+ if (Navigation.isActiveRoute(ROUTES.NEW)) {
return;
}
- Navigation.navigate(ROUTES.NEW_CHAT);
+ Navigation.navigate(ROUTES.NEW);
});
},
chatShortcutConfig.descriptionKey,
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index c5bb02354641..5c110264e034 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -334,7 +334,7 @@ const NewTeachersUniteNavigator = createModalStackNavigator([
const SaveTheWorldPage = require('../../../pages/TeachersUnite/SaveTheWorldPage').default;
return SaveTheWorldPage;
},
- name: 'SaveTheWorld_Root',
+ name: SCREENS.SAVE_THE_WORLD.ROOT,
},
{
getComponent: () => {
@@ -365,7 +365,7 @@ const SettingsModalStackNavigator = createModalStackNavigator([
const SettingsInitialPage = require('../../../pages/settings/InitialSettingsPage').default;
return SettingsInitialPage;
},
- name: 'Settings_Root',
+ name: SCREENS.SETTINGS.ROOT,
},
{
getComponent: () => {
@@ -506,7 +506,7 @@ const SettingsModalStackNavigator = createModalStackNavigator([
const SettingsSecurityPage = require('../../../pages/settings/Security/SecuritySettingsPage').default;
return SettingsSecurityPage;
},
- name: 'Settings_Security',
+ name: SCREENS.SETTINGS.SECURITY,
},
{
getComponent: () => {
@@ -550,13 +550,6 @@ const SettingsModalStackNavigator = createModalStackNavigator([
},
name: 'Settings_Wallet_Choose_Transfer_Account',
},
- {
- getComponent: () => {
- const SettingsAddPayPalMePage = require('../../../pages/settings/Wallet/AddPayPalMePage').default;
- return SettingsAddPayPalMePage;
- },
- name: 'Settings_Add_Paypal_Me',
- },
{
getComponent: () => {
const EnablePaymentsPage = require('../../../pages/EnablePayments/EnablePaymentsPage').default;
@@ -583,7 +576,7 @@ const SettingsModalStackNavigator = createModalStackNavigator([
const SettingsStatus = require('../../../pages/settings/Profile/CustomStatus/StatusPage').default;
return SettingsStatus;
},
- name: 'Settings_Status',
+ name: SCREENS.SETTINGS.STATUS,
},
{
getComponent: () => {
diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js
index b574b4ffa205..1264ec777b28 100644
--- a/src/libs/Navigation/Navigation.js
+++ b/src/libs/Navigation/Navigation.js
@@ -97,7 +97,7 @@ function navigate(route = ROUTES.HOME, type) {
* @param {Bool} shouldEnforceFallback - Enforces navigation to fallback route
* @param {Bool} shouldPopToTop - Should we navigate to LHN on back press
*/
-function goBack(fallbackRoute = ROUTES.HOME, shouldEnforceFallback = false, shouldPopToTop = false) {
+function goBack(fallbackRoute, shouldEnforceFallback = false, shouldPopToTop = false) {
if (!canNavigate('goBack')) {
return;
}
diff --git a/src/libs/Navigation/NavigationRoot.js b/src/libs/Navigation/NavigationRoot.js
index d8cb96e2c6b3..4d50a1cd6a68 100644
--- a/src/libs/Navigation/NavigationRoot.js
+++ b/src/libs/Navigation/NavigationRoot.js
@@ -103,7 +103,8 @@ function NavigationRoot(props) {
prevStatusBarBackgroundColor.current = statusBarBackgroundColor.current;
statusBarBackgroundColor.current = currentScreenBackgroundColor;
- if (prevStatusBarBackgroundColor.current === statusBarBackgroundColor.current) {
+
+ if (currentScreenBackgroundColor === themeColors.appBG && prevStatusBarBackgroundColor.current === themeColors.appBG) {
return;
}
diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js
index 14ee2b895831..f4420330fbd9 100644
--- a/src/libs/Navigation/linkingConfig.js
+++ b/src/libs/Navigation/linkingConfig.js
@@ -38,7 +38,7 @@ export default {
screens: {
Settings: {
screens: {
- Settings_Root: {
+ [SCREENS.SETTINGS.ROOT]: {
path: ROUTES.SETTINGS,
},
[SCREENS.SETTINGS.WORKSPACES]: {
@@ -65,7 +65,7 @@ export default {
path: ROUTES.SETTINGS_CLOSE,
exact: true,
},
- Settings_Security: {
+ [SCREENS.SETTINGS.SECURITY]: {
path: ROUTES.SETTINGS_SECURITY,
exact: true,
},
@@ -85,10 +85,6 @@ export default {
path: ROUTES.SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT,
exact: true,
},
- Settings_Add_Paypal_Me: {
- path: ROUTES.SETTINGS_ADD_PAYPAL_ME,
- exact: true,
- },
Settings_Add_Debit_Card: {
path: ROUTES.SETTINGS_ADD_DEBIT_CARD,
exact: true,
@@ -163,7 +159,7 @@ export default {
path: ROUTES.SETTINGS_SHARE_CODE,
exact: true,
},
- Settings_Status: {
+ [SCREENS.SETTINGS.STATUS]: {
path: ROUTES.SETTINGS_STATUS,
exact: true,
},
@@ -277,7 +273,7 @@ export default {
},
TeachersUnite: {
screens: {
- SaveTheWorld_Root: ROUTES.TEACHERS_UNITE,
+ [SCREENS.SAVE_THE_WORLD.ROOT]: ROUTES.TEACHERS_UNITE,
I_Know_A_Teacher: ROUTES.I_KNOW_A_TEACHER,
Intro_School_Principal: ROUTES.INTRO_SCHOOL_PRINCIPAL,
I_Am_A_Teacher: ROUTES.I_AM_A_TEACHER,
diff --git a/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js
new file mode 100644
index 000000000000..0afc8fe10490
--- /dev/null
+++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js
@@ -0,0 +1,15 @@
+import Airship from '@ua/react-native-airship';
+import shouldShowPushNotification from '../shouldShowPushNotification';
+
+function configureForegroundNotifications() {
+ Airship.push.android.setForegroundDisplayPredicate((pushPayload) => Promise.resolve(shouldShowPushNotification(pushPayload)));
+}
+
+function disableForegroundNotifications() {
+ Airship.push.android.setForegroundDisplayPredicate(() => Promise.resolve(false));
+}
+
+export default {
+ configureForegroundNotifications,
+ disableForegroundNotifications,
+};
diff --git a/src/libs/Notification/PushNotification/configureForegroundNotifications/index.ios.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js
similarity index 78%
rename from src/libs/Notification/PushNotification/configureForegroundNotifications/index.ios.js
rename to src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js
index 88d94b4ee805..17ad1baaebe3 100644
--- a/src/libs/Notification/PushNotification/configureForegroundNotifications/index.ios.js
+++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js
@@ -1,7 +1,7 @@
import Airship, {iOS} from '@ua/react-native-airship';
import shouldShowPushNotification from '../shouldShowPushNotification';
-export default function configureForegroundNotifications() {
+function configureForegroundNotifications() {
// Set our default iOS foreground presentation to be loud with a banner
// More info here https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate/1649518-usernotificationcenter
Airship.push.iOS.setForegroundPresentationOptions([
@@ -15,3 +15,12 @@ export default function configureForegroundNotifications() {
// Returning null keeps the default presentation. Returning [] uses no presentation (hides the notification).
Airship.push.iOS.setForegroundPresentationOptionsCallback((pushPayload) => Promise.resolve(shouldShowPushNotification(pushPayload) ? null : []));
}
+
+function disableForegroundNotifications() {
+ Airship.push.iOS.setForegroundPresentationOptionsCallback(() => Promise.resolve([]));
+}
+
+export default {
+ configureForegroundNotifications,
+ disableForegroundNotifications,
+};
diff --git a/src/libs/Notification/PushNotification/configureForegroundNotifications/index.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.js
similarity index 52%
rename from src/libs/Notification/PushNotification/configureForegroundNotifications/index.js
rename to src/libs/Notification/PushNotification/ForegroundNotifications/index.js
index c6cb13a0b3b9..acb116f7bc43 100644
--- a/src/libs/Notification/PushNotification/configureForegroundNotifications/index.js
+++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.js
@@ -1,4 +1,7 @@
/**
* Configures notification handling while in the foreground on iOS and Android. This is a no-op on other platforms.
*/
-export default function () {}
+export default {
+ configureForegroundNotifications: () => {},
+ disableForegroundNotifications: () => {},
+};
diff --git a/src/libs/Notification/PushNotification/configureForegroundNotifications/index.android.js b/src/libs/Notification/PushNotification/configureForegroundNotifications/index.android.js
deleted file mode 100644
index 393072df3d12..000000000000
--- a/src/libs/Notification/PushNotification/configureForegroundNotifications/index.android.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import Airship from '@ua/react-native-airship';
-import shouldShowPushNotification from '../shouldShowPushNotification';
-
-export default function configureForegroundNotifications() {
- Airship.push.android.setForegroundDisplayPredicate((pushPayload) => Promise.resolve(shouldShowPushNotification(pushPayload)));
-}
diff --git a/src/libs/Notification/PushNotification/index.native.js b/src/libs/Notification/PushNotification/index.native.js
index 299af69873f9..7192ee66a791 100644
--- a/src/libs/Notification/PushNotification/index.native.js
+++ b/src/libs/Notification/PushNotification/index.native.js
@@ -6,7 +6,7 @@ import Log from '../../Log';
import NotificationType from './NotificationType';
import * as PushNotification from '../../actions/PushNotification';
import ONYXKEYS from '../../../ONYXKEYS';
-import configureForegroundNotifications from './configureForegroundNotifications';
+import ForegroundNotifications from './ForegroundNotifications';
let isUserOptedInToPushNotifications = false;
Onyx.connect({
@@ -96,7 +96,7 @@ function init() {
// Keep track of which users have enabled push notifications via an NVP.
Airship.addListener(EventType.NotificationOptInStatus, refreshNotificationOptInStatus);
- configureForegroundNotifications();
+ ForegroundNotifications.configureForegroundNotifications();
}
/**
@@ -136,6 +136,7 @@ function deregister() {
Airship.contact.reset();
Airship.removeAllListeners(EventType.PushReceived);
Airship.removeAllListeners(EventType.NotificationResponse);
+ ForegroundNotifications.disableForegroundNotifications();
}
/**
diff --git a/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js b/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js
index a36fef610a39..8e16bb72f656 100644
--- a/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js
+++ b/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js
@@ -27,7 +27,7 @@ export default function subscribeToReportCommentPushNotifications() {
try {
// If a chat is visible other than the one we are trying to navigate to, then we need to navigate back
if (Navigation.getActiveRoute().slice(1, 2) === ROUTES.REPORT && !Navigation.isActiveRoute(`r/${reportID}`)) {
- Navigation.goBack();
+ Navigation.goBack(ROUTES.HOME);
}
Log.info('[PushNotification] onSelected() - Navigation is ready. Navigating...', false, {reportID, reportActionID});
diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js
index 7629a1acc0a6..3c6e879bd423 100644
--- a/src/libs/OptionsListUtils.js
+++ b/src/libs/OptionsListUtils.js
@@ -92,31 +92,30 @@ Onyx.connect({
});
/**
- * Get the options for a policy expense report.
+ * Get the option for a policy expense report.
* @param {Object} report
- * @returns {Array}
+ * @returns {Object}
*/
-function getPolicyExpenseReportOptions(report) {
+function getPolicyExpenseReportOption(report) {
const expenseReport = policyExpenseReports[`${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`];
const policyExpenseChatAvatarSource = ReportUtils.getWorkspaceAvatar(expenseReport);
const reportName = ReportUtils.getReportName(expenseReport);
- return [
- {
- ...expenseReport,
- keyForList: expenseReport.policyID,
- text: reportName,
- alternateText: Localize.translateLocal('workspace.common.workspace'),
- icons: [
- {
- source: policyExpenseChatAvatarSource,
- name: reportName,
- type: CONST.ICON_TYPE_WORKSPACE,
- },
- ],
- selected: report.selected,
- isPolicyExpenseChat: true,
- },
- ];
+ return {
+ ...expenseReport,
+ keyForList: expenseReport.policyID,
+ text: reportName,
+ alternateText: Localize.translateLocal('workspace.common.workspace'),
+ icons: [
+ {
+ source: policyExpenseChatAvatarSource,
+ name: reportName,
+ type: CONST.ICON_TYPE_WORKSPACE,
+ },
+ ],
+ selected: report.selected,
+ isPolicyExpenseChat: true,
+ searchText: report.searchText,
+ };
}
/**
@@ -201,38 +200,35 @@ function isPersonalDetailsReady(personalDetails) {
}
/**
- * Get the participant options for a report.
- * @param {Array
diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js
index 0b850e6c3849..1a9a2d8c8767 100644
--- a/src/pages/FlagCommentPage.js
+++ b/src/pages/FlagCommentPage.js
@@ -2,6 +2,7 @@ import React, {useCallback} from 'react';
import _ from 'underscore';
import {View, ScrollView} from 'react-native';
import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
import reportPropTypes from './reportPropTypes';
import reportActionPropTypes from './home/report/reportActionPropTypes';
import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
@@ -20,6 +21,7 @@ import * as ReportActionsUtils from '../libs/ReportActionsUtils';
import * as Session from '../libs/actions/Session';
import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
import withReportAndReportActionOrNotFound from './home/report/withReportAndReportActionOrNotFound';
+import ONYXKEYS from '../ONYXKEYS';
const propTypes = {
/** Array of report actions for this report */
@@ -178,4 +180,13 @@ FlagCommentPage.propTypes = propTypes;
FlagCommentPage.defaultProps = defaultProps;
FlagCommentPage.displayName = 'FlagCommentPage';
-export default compose(withLocalize, withReportAndReportActionOrNotFound)(FlagCommentPage);
+export default compose(
+ withLocalize,
+ withReportAndReportActionOrNotFound,
+ withOnyx({
+ parentReportActions: {
+ key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.parentReportID || report.reportID}`,
+ canEvict: false,
+ },
+ }),
+)(FlagCommentPage);
diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js
index e72cb9a3f79b..cb54aa8e5a7b 100755
--- a/src/pages/NewChatPage.js
+++ b/src/pages/NewChatPage.js
@@ -55,8 +55,9 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate})
const headerMessage = OptionsListUtils.getHeaderMessage(
filteredPersonalDetails.length + filteredRecentReports.length !== 0,
Boolean(filteredUserToInvite),
- searchTerm,
+ searchTerm.trim(),
maxParticipantsReached,
+ _.some(selectedOptions, (participant) => participant.searchText.toLowerCase().includes(searchTerm.trim().toLowerCase())),
);
const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails);
@@ -123,7 +124,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate})
recentReports,
personalDetails: newChatPersonalDetails,
userToInvite,
- } = OptionsListUtils.getNewChatOptions(reports, personalDetails, betas, searchTerm, newSelectedOptions, excludedGroupEmails);
+ } = OptionsListUtils.getFilteredOptions(reports, personalDetails, betas, searchTerm, newSelectedOptions, excludedGroupEmails);
setSelectedOptions(newSelectedOptions);
setFilteredRecentReports(recentReports);
@@ -158,7 +159,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate})
recentReports,
personalDetails: newChatPersonalDetails,
userToInvite,
- } = OptionsListUtils.getNewChatOptions(reports, personalDetails, betas, searchTerm, selectedOptions, isGroupChat ? excludedGroupEmails : []);
+ } = OptionsListUtils.getFilteredOptions(reports, personalDetails, betas, searchTerm, selectedOptions, isGroupChat ? excludedGroupEmails : []);
setFilteredRecentReports(recentReports);
setFilteredPersonalDetails(newChatPersonalDetails);
setFilteredUserToInvite(userToInvite);
diff --git a/src/pages/NewChatSelectorPage.js b/src/pages/NewChatSelectorPage.js
index 89a3fd1adc72..ce0bbda0d239 100755
--- a/src/pages/NewChatSelectorPage.js
+++ b/src/pages/NewChatSelectorPage.js
@@ -1,4 +1,5 @@
import React from 'react';
+import {withOnyx} from 'react-native-onyx';
import OnyxTabNavigator, {TopTab} from '../libs/Navigation/OnyxTabNavigator';
import TabSelector from '../components/TabSelector/TabSelector';
import Navigation from '../libs/Navigation/Navigation';
@@ -6,6 +7,7 @@ import Permissions from '../libs/Permissions';
import NewChatPage from './NewChatPage';
import WorkspaceNewRoomPage from './workspace/WorkspaceNewRoomPage';
import CONST from '../CONST';
+import ONYXKEYS from '../ONYXKEYS';
import withWindowDimensions, {windowDimensionsPropTypes} from '../components/withWindowDimensions';
import HeaderWithBackButton from '../components/HeaderWithBackButton';
import ScreenWrapper from '../components/ScreenWrapper';
@@ -66,4 +68,10 @@ NewChatSelectorPage.propTypes = propTypes;
NewChatSelectorPage.defaultProps = defaultProps;
NewChatSelectorPage.displayName = 'NewChatPage';
-export default compose(withLocalize, withWindowDimensions)(NewChatSelectorPage);
+export default compose(
+ withLocalize,
+ withWindowDimensions,
+ withOnyx({
+ betas: {key: ONYXKEYS.BETAS},
+ }),
+)(NewChatSelectorPage);
diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.js b/src/pages/PrivateNotes/PrivateNotesEditPage.js
index 4cada83941ac..206e9e74d91f 100644
--- a/src/pages/PrivateNotes/PrivateNotesEditPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js
@@ -24,6 +24,7 @@ import * as Report from '../../libs/actions/Report';
import useLocalize from '../../hooks/useLocalize';
import OfflineWithFeedback from '../../components/OfflineWithFeedback';
import focusAndUpdateMultilineInputRange from '../../libs/focusAndUpdateMultilineInputRange';
+import ROUTES from '../../ROUTES';
const propTypes = {
/** All of the personal details for everyone */
@@ -72,7 +73,7 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
Keyboard.dismiss();
// Take user back to the PrivateNotesView page
- Navigation.goBack();
+ Navigation.goBack(ROUTES.HOME);
};
return (
@@ -83,14 +84,12 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
Navigation.goBack()}
>
Navigation.dismissModal()}
- onBackButtonPress={() => Navigation.goBack()}
/>
diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.js b/src/pages/PrivateNotes/PrivateNotesListPage.js
index 5ea081a12f25..098bfd2a245b 100644
--- a/src/pages/PrivateNotes/PrivateNotesListPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesListPage.js
@@ -107,26 +107,22 @@ function PrivateNotesListPage({report, personalDetailsList, network, session}) {
const privateNoteBrickRoadIndicator = (accountID) => (!_.isEmpty(lodashGet(report, ['privateNotes', accountID, 'errors'], '')) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '');
return _.chain(lodashGet(report, 'privateNotes', {}))
.map((privateNote, accountID) => ({
- title: Number(lodashGet(session, 'accountID', null)) === Number(accountID) ? 'My note' : lodashGet(personalDetailsList, [accountID, 'login'], ''),
+ title: Number(lodashGet(session, 'accountID', null)) === Number(accountID) ? translate('privateNotes.myNote') : lodashGet(personalDetailsList, [accountID, 'login'], ''),
icon: UserUtils.getAvatar(lodashGet(personalDetailsList, [accountID, 'avatar'], UserUtils.getDefaultAvatar(accountID)), accountID),
iconType: CONST.ICON_TYPE_AVATAR,
action: () => Navigation.navigate(ROUTES.getPrivateNotesViewRoute(report.reportID, accountID)),
brickRoadIndicator: privateNoteBrickRoadIndicator(accountID),
}))
.value();
- }, [report, personalDetailsList, session]);
+ }, [report, personalDetailsList, session, translate]);
return (
- Navigation.goBack()}
- >
+
Navigation.dismissModal()}
- onBackButtonPress={() => Navigation.goBack()}
/>
{report.isLoadingPrivateNotes && _.isEmpty(lodashGet(report, 'privateNotes', {})) ? (
diff --git a/src/pages/PrivateNotes/PrivateNotesViewPage.js b/src/pages/PrivateNotes/PrivateNotesViewPage.js
index 86814ed4dc92..48f053f10f90 100644
--- a/src/pages/PrivateNotes/PrivateNotesViewPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesViewPage.js
@@ -60,14 +60,12 @@ function PrivateNotesViewPage({route, personalDetailsList, session, report}) {
Navigation.goBack()}
>
Navigation.dismissModal()}
- onBackButtonPress={() => Navigation.goBack()}
/>
diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js
index 19f2b1fdc0c6..b515da04b7be 100755
--- a/src/pages/ProfilePage.js
+++ b/src/pages/ProfilePage.js
@@ -139,7 +139,7 @@ function ProfilePage(props) {
const hasStatus = !!statusEmojiCode && Permissions.canUseCustomStatus(props.betas);
const statusContent = `${statusEmojiCode} ${statusText}`;
- const navigateBackTo = lodashGet(props.route, 'params.backTo', '');
+ const navigateBackTo = lodashGet(props.route, 'params.backTo', ROUTES.HOME);
const chatReportWithCurrentUser = !isCurrentUser && !Session.isAnonymousUser() ? ReportUtils.getChatByParticipants([accountID]) : 0;
diff --git a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js
index 80c9257d367a..70cf43fcfdc2 100644
--- a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js
+++ b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js
@@ -1,4 +1,5 @@
-import React, {useCallback} from 'react';
+import React, {useCallback, useEffect} from 'react';
+import {useIsFocused} from '@react-navigation/native';
import PropTypes from 'prop-types';
import _ from 'underscore';
import lodashGet from 'lodash/get';
@@ -41,6 +42,7 @@ const defaultProps = {
function BankAccountPlaidStep(props) {
const {plaidData, receivedRedirectURI, plaidLinkOAuthToken, reimbursementAccount, reimbursementAccountDraft, onBackButtonPress, getDefaultStateForField, translate} = props;
+ const isFocused = useIsFocused();
const validate = useCallback((values) => {
const errorFields = {};
@@ -51,6 +53,14 @@ function BankAccountPlaidStep(props) {
return errorFields;
}, []);
+ useEffect(() => {
+ const plaidBankAccounts = lodashGet(plaidData, 'bankAccounts') || [];
+ if (isFocused || plaidBankAccounts.length) {
+ return;
+ }
+ BankAccounts.setBankAccountSubStep(null);
+ }, [isFocused, plaidData]);
+
const submit = useCallback(() => {
const selectedPlaidBankAccount = _.findWhere(lodashGet(plaidData, 'bankAccounts', []), {
plaidAccountID: lodashGet(reimbursementAccountDraft, 'plaidAccountID', ''),
@@ -103,7 +113,6 @@ function BankAccountPlaidStep(props) {
}}
plaidData={plaidData}
onExitPlaid={() => BankAccounts.setBankAccountSubStep(null)}
- onBlurPlaid={() => BankAccounts.setBankAccountSubStep(null)}
receivedRedirectURI={receivedRedirectURI}
plaidLinkOAuthToken={plaidLinkOAuthToken}
allowDebit
diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js
index 3160ad590c50..cdb3aeebe924 100644
--- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js
+++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js
@@ -284,7 +284,7 @@ class ReimbursementAccountPage extends React.Component {
const currentStep = achData.currentStep || CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT;
const subStep = achData.subStep;
const shouldShowOnfido = this.props.onfidoToken && !achData.isOnfidoSetupComplete;
- const backTo = lodashGet(this.props.route.params, 'backTo');
+ const backTo = lodashGet(this.props.route.params, 'backTo', ROUTES.HOME);
switch (currentStep) {
case CONST.BANK_ACCOUNT.STEP.BANK_ACCOUNT:
if (this.hasInProgressVBBA()) {
@@ -405,7 +405,7 @@ class ReimbursementAccountPage extends React.Component {
continue={this.continue}
policyName={policyName}
onBackButtonPress={() => {
- Navigation.goBack(lodashGet(this.props.route.params, 'backTo'));
+ Navigation.goBack(lodashGet(this.props.route.params, 'backTo', ROUTES.HOME));
}}
/>
);
diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js
index a81d02c60b36..a36149a5f4fa 100644
--- a/src/pages/ShareCodePage.js
+++ b/src/pages/ShareCodePage.js
@@ -42,8 +42,9 @@ class ShareCodePage extends React.Component {
render() {
const isReport = this.props.report != null && this.props.report.reportID != null;
- const subtitle = ReportUtils.getChatRoomSubtitle(this.props.report);
-
+ const title = isReport ? ReportUtils.getReportName(this.props.report) : this.props.currentUserPersonalDetails.displayName;
+ const formattedEmail = this.props.formatPhoneNumber(this.props.session.email);
+ const subtitle = isReport ? ReportUtils.getParentNavigationSubtitle(this.props.report).workspaceName || ReportUtils.getChatRoomSubtitle(this.props.report) : formattedEmail;
const urlWithTrailingSlash = Url.addTrailingForwardSlash(this.props.environmentURL);
const url = isReport
? `${urlWithTrailingSlash}${ROUTES.getReportRoute(this.props.report.reportID)}`
@@ -51,7 +52,6 @@ class ShareCodePage extends React.Component {
const platform = getPlatform();
const isNative = platform === CONST.PLATFORM.IOS || platform === CONST.PLATFORM.ANDROID;
- const formattedEmail = this.props.formatPhoneNumber(this.props.session.email);
return (
@@ -65,8 +65,8 @@ class ShareCodePage extends React.Component {
Navigation.goBack(ROUTES.HOME)}
illustration={LottieAnimations.SaveTheWorld}
>
diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js
index 8d389a8c8581..477d063c1747 100644
--- a/src/pages/home/HeaderView.js
+++ b/src/pages/home/HeaderView.js
@@ -29,6 +29,7 @@ import reportActionPropTypes from './report/reportActionPropTypes';
import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback';
import PinButton from '../../components/PinButton';
import TaskHeaderActionButton from '../../components/TaskHeaderActionButton';
+import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
import ParentNavigationSubtitle from '../../components/ParentNavigationSubtitle';
const propTypes = {
@@ -93,12 +94,14 @@ function HeaderView(props) {
const isConcierge = ReportUtils.hasSingleParticipant(props.report) && _.contains(participants, CONST.ACCOUNT_ID.CONCIERGE);
const isAutomatedExpensifyAccount = ReportUtils.hasSingleParticipant(props.report) && ReportUtils.hasAutomatedExpensifyAccountIDs(participants);
const guideCalendarLink = lodashGet(props.account, 'guideCalendarLink');
+ const parentReportAction = ReportActionsUtils.getParentReportAction(props.report);
+ const isCanceledTaskReport = ReportUtils.isCanceledTaskReport(props.report, parentReportAction);
// We hide the button when we are chatting with an automated Expensify account since it's not possible to contact
// these users via alternative means. It is possible to request a call with Concierge so we leave the option for them.
const shouldShowCallButton = (isConcierge && guideCalendarLink) || (!isAutomatedExpensifyAccount && !isTaskReport);
const threeDotMenuItems = [];
- if (isTaskReport) {
+ if (isTaskReport && !isCanceledTaskReport) {
const canModifyTask = Task.canModifyTask(props.report, props.session.accountID);
if (ReportUtils.isOpenTaskReport(props.report) && canModifyTask) {
threeDotMenuItems.push({
diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js
index a4145843ab87..63e60a545de9 100644
--- a/src/pages/home/ReportScreen.js
+++ b/src/pages/home/ReportScreen.js
@@ -1,5 +1,6 @@
import React, {useRef, useState, useEffect, useMemo, useCallback} from 'react';
import {withOnyx} from 'react-native-onyx';
+import {useFocusEffect} from '@react-navigation/native';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import lodashGet from 'lodash/get';
@@ -259,26 +260,28 @@ function ReportScreen({
[route],
);
- useEffect(() => {
- const unsubscribeVisibilityListener = Visibility.onVisibilityChange(() => {
- const isTopMostReportID = Navigation.getTopmostReportId() === getReportID(route);
- // If the report is not fully visible (AKA on small screen devices and LHR is open) or the report is optimistic (AKA not yet created)
- // we don't need to call openReport
- if (!getIsReportFullyVisible(isTopMostReportID) || report.isOptimisticReport) {
- return;
- }
-
- Report.openReport(report.reportID);
- });
+ useFocusEffect(
+ useCallback(() => {
+ const unsubscribeVisibilityListener = Visibility.onVisibilityChange(() => {
+ const isTopMostReportID = Navigation.getTopmostReportId() === getReportID(route);
+ // If the report is not fully visible (AKA on small screen devices and LHR is open) or the report is optimistic (AKA not yet created)
+ // we don't need to call openReport
+ if (!getIsReportFullyVisible(isTopMostReportID) || report.isOptimisticReport) {
+ return;
+ }
+
+ Report.openReport(report.reportID);
+ });
+
+ return () => unsubscribeVisibilityListener();
+ // The effect should run only on the first focus to attach listener
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []),
+ );
+ useEffect(() => {
fetchReportIfNeeded();
ComposerActions.setShouldShowComposeInput(true);
- return () => {
- if (!unsubscribeVisibilityListener) {
- return;
- }
- unsubscribeVisibilityListener();
- };
// I'm disabling the warning, as it expects to use exhaustive deps, even though we want this useEffect to run only on the first render.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@@ -325,7 +328,6 @@ function ReportScreen({
subtitleKey="notFound.noAccess"
shouldShowCloseButton={false}
shouldShowBackButton={isSmallScreenWidth}
- onBackButtonPress={Navigation.goBack}
shouldShowLink={false}
>
{headerView}
- {ReportUtils.isTaskReport(report) && isSmallScreenWidth && ReportUtils.isOpenTaskReport(report) && (
+ {ReportUtils.isTaskReport(report) && isSmallScreenWidth && ReportUtils.isOpenTaskReport(report, parentReportAction) && (
diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js
index 3f4a5fe3ac4c..6382af6a898e 100755
--- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js
+++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js
@@ -49,7 +49,9 @@ function BaseReportActionContextMenu(props) {
const wrapperStyle = getReportActionContextMenuStyles(props.isMini, props.isSmallScreenWidth);
const reportAction = useMemo(() => {
- if (_.isEmpty(props.reportActions) || props.reportActionID === '0') return {};
+ if (_.isEmpty(props.reportActions) || props.reportActionID === '0') {
+ return {};
+ }
return props.reportActions[props.reportActionID] || {};
}, [props.reportActions, props.reportActionID]);
diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js
index 556366a96792..173bda0e5221 100644
--- a/src/pages/home/report/ContextMenu/ContextMenuActions.js
+++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js
@@ -21,6 +21,10 @@ import QuickEmojiReactions from '../../../../components/Reactions/QuickEmojiReac
import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickEmojiReactions';
import Navigation from '../../../../libs/Navigation/Navigation';
import ROUTES from '../../../../ROUTES';
+import * as Task from '../../../../libs/actions/Task';
+import * as Localize from '../../../../libs/Localize';
+import * as TransactionUtils from '../../../../libs/TransactionUtils';
+import * as CurrencyUtils from '../../../../libs/CurrencyUtils';
/**
* Gets the HTML version of the message in an action.
@@ -182,10 +186,11 @@ export default [
// the `text` and `icon`
onPress: (closePopover, {reportAction, selection}) => {
const isTaskAction = ReportActionsUtils.isTaskAction(reportAction);
+ const isCreateTaskAction = ReportActionsUtils.isCreatedTaskReportAction(reportAction);
const isReportPreviewAction = ReportActionsUtils.isReportPreviewAction(reportAction);
const message = _.last(lodashGet(reportAction, 'message', [{}]));
- const originalMessage = _.get(reportAction, 'originalMessage', {});
- const messageHtml = isTaskAction ? lodashGet(originalMessage, 'html', '') : lodashGet(message, 'html', '');
+ const reportID = lodashGet(reportAction, 'originalMessage.taskReportID', '').toString();
+ const messageHtml = isTaskAction || isCreateTaskAction ? Task.getTaskReportActionMessage(reportAction.actionName, reportID, isCreateTaskAction) : lodashGet(message, 'html', '');
const isAttachment = ReportActionsUtils.isReportActionAttachment(reportAction);
if (!isAttachment) {
@@ -197,6 +202,16 @@ export default [
} else if (ReportActionsUtils.isModifiedExpenseAction(reportAction)) {
const modifyExpenseMessage = ReportUtils.getModifiedExpenseMessage(reportAction);
Clipboard.setString(modifyExpenseMessage);
+ } else if (ReportActionsUtils.isMoneyRequestAction(reportAction)) {
+ const originalMessage = _.get(reportAction, 'originalMessage', {});
+ const transaction = TransactionUtils.getTransaction(originalMessage.IOUTransactionID);
+ const {amount, currency, comment} = ReportUtils.getTransactionDetails(transaction);
+ const formattedAmount = CurrencyUtils.convertToDisplayString(amount, currency);
+ const displaymessage = Localize.translateLocal('iou.requestedAmount', {
+ formattedAmount,
+ comment,
+ });
+ Clipboard.setString(displaymessage);
} else if (content) {
const parser = new ExpensiMark();
if (!Clipboard.canSetHtml()) {
diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
index 04757b0ff276..ccf7a0a51518 100644
--- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
+++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
@@ -185,6 +185,11 @@ function ComposerWithSuggestions({
setIsCommentEmpty(!!newComment.match(/^(\s)*$/));
setValue(newComment);
if (commentValue !== newComment) {
+ // Ensure emoji suggestions are hidden even when the selection is not changed (so calculateEmojiSuggestion would not be called).
+ if (suggestionsRef.current) {
+ suggestionsRef.current.resetSuggestions();
+ }
+
const remainder = ComposerUtils.getCommonSuffixLength(commentRef.current, newComment);
setSelection({
start: newComment.length - remainder,
@@ -212,7 +217,7 @@ function ComposerWithSuggestions({
debouncedBroadcastUserIsTyping(reportID);
}
},
- [debouncedUpdateFrequentlyUsedEmojis, preferredLocale, preferredSkinTone, reportID, setIsCommentEmpty],
+ [debouncedUpdateFrequentlyUsedEmojis, preferredLocale, preferredSkinTone, reportID, setIsCommentEmpty, suggestionsRef],
);
/**
@@ -241,6 +246,11 @@ function ComposerWithSuggestions({
return '';
}
+ // Since we're submitting the form here which should clear the composer
+ // We don't really care about saving the draft the user was typing
+ // We need to make sure an empty draft gets saved instead
+ debouncedSaveReportComment.cancel();
+
updateComment('');
setTextInputShouldClear(true);
if (isComposerFullSize) {
diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js
index ddcd43cd8cd0..c5179290bf2c 100644
--- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js
+++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js
@@ -30,7 +30,6 @@ import OfflineWithFeedback from '../../../../components/OfflineWithFeedback';
import SendButton from './SendButton';
import AttachmentPickerWithMenuItems from './AttachmentPickerWithMenuItems';
import ComposerWithSuggestions from './ComposerWithSuggestions';
-import debouncedSaveReportComment from '../../../../libs/ComposerUtils/debouncedSaveReportComment';
import reportActionPropTypes from '../reportActionPropTypes';
import useLocalize from '../../../../hooks/useLocalize';
import getModalState from '../../../../libs/getModalState';
@@ -220,10 +219,6 @@ function ReportActionCompose({
*/
const addAttachment = useCallback(
(file) => {
- // Since we're submitting the form here which should clear the composer
- // We don't really care about saving the draft the user was typing
- // We need to make sure an empty draft gets saved instead
- debouncedSaveReportComment.cancel();
const newComment = composerRef.current.prepareCommentAndResetComposer();
Report.addAttachment(reportID, file, newComment);
setTextInputShouldClear(false);
@@ -251,11 +246,6 @@ function ReportActionCompose({
e.preventDefault();
}
- // Since we're submitting the form here which should clear the composer
- // We don't really care about saving the draft the user was typing
- // We need to make sure an empty draft gets saved instead
- debouncedSaveReportComment.cancel();
-
const newComment = composerRef.current.prepareCommentAndResetComposer();
if (!newComment) {
return;
diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js
index fae5c518bbfe..8cf8fd78371d 100644
--- a/src/pages/home/report/ReportActionItem.js
+++ b/src/pages/home/report/ReportActionItem.js
@@ -67,6 +67,7 @@ import * as BankAccounts from '../../../libs/actions/BankAccounts';
import usePrevious from '../../../hooks/usePrevious';
import ReportScreenContext from '../ReportScreenContext';
import Permissions from '../../../libs/Permissions';
+import RenderHTML from '../../../components/RenderHTML';
import ReportAttachmentsContext from './ReportAttachmentsContext';
const propTypes = {
@@ -520,6 +521,22 @@ function ReportActionItem(props) {
);
}
if (ReportUtils.isTaskReport(props.report)) {
+ if (ReportUtils.isCanceledTaskReport(props.report, parentReportAction)) {
+ return (
+ <>
+
+ ${props.translate('parentReportAction.deletedTask')}`} />
+
+
+ >
+ );
+ }
+
return (
-
+
{(hovered) => (
{props.shouldDisplayNewMarker && }
@@ -603,6 +623,7 @@ function ReportActionItem(props) {
errors={props.action.errors}
errorRowStyles={[styles.ml10, styles.mr2]}
needsOffscreenAlphaCompositing={ReportActionsUtils.isMoneyRequestAction(props.action)}
+ shouldDisableStrikeThrough
>
{isWhisper && (
diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js
index e9fd30f5b057..1f61b44841bc 100644
--- a/src/pages/home/report/ReportActionItemFragment.js
+++ b/src/pages/home/report/ReportActionItemFragment.js
@@ -16,7 +16,6 @@ import compose from '../../../libs/compose';
import convertToLTR from '../../../libs/convertToLTR';
import {withNetwork} from '../../../components/OnyxProvider';
import CONST from '../../../CONST';
-import applyStrikethrough from '../../../components/HTMLEngineProvider/applyStrikethrough';
import editedLabelStyles from '../../../styles/editedLabelStyles';
import UserDetailsTooltip from '../../../components/UserDetailsTooltip';
import avatarPropTypes from '../../../components/avatarPropTypes';
@@ -112,6 +111,7 @@ function ReportActionItemFragment(props) {
);
}
const {html, text} = props.fragment;
+ const isPendingDelete = props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && props.network.isOffline;
// Threaded messages display "[Deleted message]" instead of being hidden altogether.
// While offline we display the previous message with a strikethrough style. Once online we want to
@@ -128,35 +128,40 @@ function ReportActionItemFragment(props) {
// Only render HTML if we have html in the fragment
if (!differByLineBreaksOnly) {
- const isPendingDelete = props.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE && props.network.isOffline;
const editedTag = props.fragment.isEdited ? `` : '';
- const htmlContent = applyStrikethrough(html + editedTag, isPendingDelete);
+ const htmlContent = isPendingDelete ? `${html}` : html;
- return ${htmlContent}` : `${htmlContent}`} />;
+ const htmlWithTag = editedTag ? `${htmlContent}${editedTag}` : htmlContent;
+
+ return ${htmlWithTag}` : `${htmlWithTag}`} />;
}
const containsOnlyEmojis = EmojiUtils.containsOnlyEmojis(text);
return (
-
- {convertToLTR(props.iouMessage || text)}
+
+
+ {convertToLTR(props.iouMessage || text)}
+
{Boolean(props.fragment.isEdited) && (
-
+ <>
{' '}
- {props.translate('reportActionCompose.edited')}
-
+
+ {props.translate('reportActionCompose.edited')}
+
+ >
)}
);
diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js
index 7f897ee825fb..19270ff13f45 100644
--- a/src/pages/home/report/ReportActionsList.js
+++ b/src/pages/home/report/ReportActionsList.js
@@ -74,6 +74,12 @@ const MSG_VISIBLE_THRESHOLD = 250;
// the useRef value gets reset when the reportID changes, so we use a global variable to keep track
let prevReportID = null;
+// In the component we are subscribing to the arrival of new actions.
+// As there is the possibility that there are multiple instances of a ReportScreen
+// for the same report, we only ever want one subscription to be active, as
+// the subscriptions could otherwise be conflicting.
+const newActionUnsubscribeMap = {};
+
/**
* Create a unique key for each action in the FlatList.
* We use the reportActionID that is a string representation of a random 64-bit int, which should be
@@ -109,7 +115,7 @@ function ReportActionsList({
const {isOffline} = useNetwork();
const opacity = useSharedValue(0);
const userActiveSince = useRef(null);
- const currentUnreadMarker = useRef(null);
+ const [currentUnreadMarker, setCurrentUnreadMarker] = useState(null);
const scrollingVerticalOffset = useRef(0);
const readActionSkipped = useRef(false);
const reportActionSize = useRef(sortedReportActions.length);
@@ -152,12 +158,12 @@ function ReportActionsList({
}
}
- if (currentUnreadMarker.current || reportActionSize.current === sortedReportActions.length) {
+ if (currentUnreadMarker || reportActionSize.current === sortedReportActions.length) {
return;
}
reportActionSize.current = sortedReportActions.length;
- currentUnreadMarker.current = null;
+ setCurrentUnreadMarker(null);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [sortedReportActions.length, report.reportID]);
@@ -169,18 +175,56 @@ function ReportActionsList({
}
// Clearing the current unread marker so that it can be recalculated
- currentUnreadMarker.current = null;
+ setCurrentUnreadMarker(null);
setMessageManuallyMarked({read: true});
// We only care when a new lastReadTime is set in the report
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [report.lastReadTime]);
+ useEffect(() => {
+ // Why are we doing this, when in the cleanup of the useEffect we are already calling the unsubscribe function?
+ // Answer: On web, when navigating to another report screen, the previous report screen doesn't get unmounted,
+ // meaning that the cleanup might not get called. When we then open a report we had open already previosuly, a new
+ // ReportScreen will get created. Thus, we have to cancel the earlier subscription of the previous screen,
+ // because the two subscriptions could conflict!
+ // In case we return to the previous screen (e.g. by web back navigation) the useEffect for that screen would
+ // fire again, as the focus has changed and will set up the subscription correctly again.
+ const previousSubUnsubscribe = newActionUnsubscribeMap[report.reportID];
+ if (previousSubUnsubscribe) {
+ previousSubUnsubscribe();
+ }
+
+ // This callback is triggered when a new action arrives via Pusher and the event is emitted from Report.js. This allows us to maintain
+ // a single source of truth for the "new action" event instead of trying to derive that a new action has appeared from looking at props.
+ const unsubscribe = Report.subscribeToNewActionEvent(report.reportID, (isFromCurrentUser) => {
+ // If a new comment is added and it's from the current user scroll to the bottom otherwise leave the user positioned where
+ // they are now in the list.
+ if (!isFromCurrentUser) {
+ return;
+ }
+ reportScrollManager.scrollToBottom();
+ });
+
+ const cleanup = () => {
+ if (unsubscribe) {
+ unsubscribe();
+ }
+ Report.unsubscribeFromReportChannel(report.reportID);
+ };
+
+ newActionUnsubscribeMap[report.reportID] = cleanup;
+
+ return cleanup;
+
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [report.reportID]);
+
/**
* Show/hide the new floating message counter when user is scrolling back/forth in the history of messages.
*/
const handleUnreadFloatingButton = () => {
- if (scrollingVerticalOffset.current > VERTICAL_OFFSET_THRESHOLD && !isFloatingMessageCounterVisible && !!currentUnreadMarker.current) {
+ if (scrollingVerticalOffset.current > VERTICAL_OFFSET_THRESHOLD && !isFloatingMessageCounterVisible && !!currentUnreadMarker) {
setIsFloatingMessageCounterVisible(true);
}
@@ -216,6 +260,15 @@ function ReportActionsList({
return Math.ceil(availableHeight / minimumReportActionHeight);
}, [windowHeight]);
+ /**
+ * Thread's divider line should hide when the first chat in the thread is marked as unread.
+ * This is so that it will not be conflicting with header's separator line.
+ */
+ const shouldHideThreadDividerLine = useMemo(
+ () => sortedReportActions.length > 1 && sortedReportActions[sortedReportActions.length - 2].reportActionID === currentUnreadMarker,
+ [sortedReportActions, currentUnreadMarker],
+ );
+
/**
* @param {Object} args
* @param {Number} args.index
@@ -225,7 +278,7 @@ function ReportActionsList({
({item: reportAction, index}) => {
let shouldDisplayNewMarker = false;
- if (!currentUnreadMarker.current) {
+ if (!currentUnreadMarker) {
const nextMessage = sortedReportActions[index + 1];
const isCurrentMessageUnread = isMessageUnread(reportAction, report.lastReadTime);
shouldDisplayNewMarker = isCurrentMessageUnread && !isMessageUnread(nextMessage, report.lastReadTime);
@@ -235,18 +288,17 @@ function ReportActionsList({
}
const canDisplayMarker = scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD ? reportAction.created < userActiveSince.current : true;
- if (!currentUnreadMarker.current && shouldDisplayNewMarker && canDisplayMarker) {
- currentUnreadMarker.current = reportAction.reportActionID;
+ if (!currentUnreadMarker && shouldDisplayNewMarker && canDisplayMarker) {
+ setCurrentUnreadMarker(reportAction.reportActionID);
}
} else {
- shouldDisplayNewMarker = reportAction.reportActionID === currentUnreadMarker.current;
+ shouldDisplayNewMarker = reportAction.reportActionID === currentUnreadMarker;
}
const shouldDisplayParentAction =
reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED &&
ReportUtils.isChatThread(report) &&
!ReportActionsUtils.isTransactionThread(ReportActionsUtils.getParentReportAction(report));
- const shouldHideThreadDividerLine = sortedReportActions.length > 1 && sortedReportActions[sortedReportActions.length - 2].reportActionID === currentUnreadMarker.current;
return shouldDisplayParentAction ? (
);
},
- [report, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, messageManuallyMarked],
+ [report, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, messageManuallyMarked, shouldHideThreadDividerLine, currentUnreadMarker],
);
// Native mobile does not render updates flatlist the changes even though component did update called.
// To notify there something changes we can use extraData prop to flatlist
- const extraData = [isSmallScreenWidth ? currentUnreadMarker.current : undefined, ReportUtils.isArchivedRoom(report)];
+ const extraData = [isSmallScreenWidth ? currentUnreadMarker : undefined, ReportUtils.isArchivedRoom(report)];
const hideComposer = ReportUtils.shouldDisableWriteActions(report);
const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(personalDetailsList, report, currentUserPersonalDetails.accountID) && !isComposerFullSize;
return (
<>
interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)),
},
- {
- icon: Expensicons.Heart,
- text: props.translate('sidebarScreen.saveTheWorld'),
- onSelected: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.TEACHERS_UNITE)),
- },
...(Permissions.canUseTasks(props.betas)
? [
{
diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js
index 705d9d1e2d08..08888352ddff 100755
--- a/src/pages/home/sidebar/SidebarScreen/index.js
+++ b/src/pages/home/sidebar/SidebarScreen/index.js
@@ -23,18 +23,28 @@ function SidebarScreen(props) {
}, []),
);
+ /**
+ * Method to hide popover when dragover.
+ */
+ const hidePopoverOnDragOver = useCallback(() => {
+ if (!popoverModal.current) {
+ return;
+ }
+ popoverModal.current.hideCreateMenu();
+ }, []);
+
/**
* Method create event listener
*/
const createDragoverListener = () => {
- document.addEventListener('dragover', () => popoverModal.current.hideCreateMenu());
+ document.addEventListener('dragover', hidePopoverOnDragOver);
};
/**
* Method remove event listener.
*/
const removeDragoverListener = () => {
- document.removeEventListener('dragover', () => popoverModal.current.hideCreateMenu());
+ document.removeEventListener('dragover', hidePopoverOnDragOver);
};
return (
diff --git a/src/pages/iou/IOUCurrencySelection.js b/src/pages/iou/IOUCurrencySelection.js
index 80f4a5c17e23..1238d8934f75 100644
--- a/src/pages/iou/IOUCurrencySelection.js
+++ b/src/pages/iou/IOUCurrencySelection.js
@@ -83,7 +83,7 @@ function IOUCurrencySelection(props) {
// Navigating to "backTo" will result in forward navigation instead, causing disruption to the currency selection.
// To prevent any negative experience, we have made the decision to simply close the currency selection page.
if (_.isEmpty(backTo) || props.navigation.getState().routes.length === 1) {
- Navigation.goBack();
+ Navigation.goBack(ROUTES.HOME);
} else {
Navigation.navigate(`${props.route.params.backTo}?currency=${option.currencyCode}`);
}
@@ -104,7 +104,7 @@ function IOUCurrencySelection(props) {
};
});
- const searchRegex = new RegExp(Str.escapeForRegExp(searchValue), 'i');
+ const searchRegex = new RegExp(Str.escapeForRegExp(searchValue.trim()), 'i');
const filteredCurrencies = _.filter(currencyOptions, (currencyOption) => searchRegex.test(currencyOption.text));
const isEmpty = searchValue.trim() && !filteredCurrencies.length;
diff --git a/src/pages/iou/MoneyRequestTagPage.js b/src/pages/iou/MoneyRequestTagPage.js
index a1795d50df8a..c9b5eb4f8f6f 100644
--- a/src/pages/iou/MoneyRequestTagPage.js
+++ b/src/pages/iou/MoneyRequestTagPage.js
@@ -5,6 +5,7 @@ import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
import compose from '../../libs/compose';
import ROUTES from '../../ROUTES';
+import * as IOU from '../../libs/actions/IOU';
import Navigation from '../../libs/Navigation/Navigation';
import useLocalize from '../../hooks/useLocalize';
import ScreenWrapper from '../../components/ScreenWrapper';
@@ -15,6 +16,7 @@ import tagPropTypes from '../../components/tagPropTypes';
import ONYXKEYS from '../../ONYXKEYS';
import reportPropTypes from '../reportPropTypes';
import styles from '../../styles/styles';
+import {iouPropTypes, iouDefaultProps} from './propTypes';
const propTypes = {
/** Navigation route context info provided by react navigation */
@@ -40,14 +42,18 @@ const propTypes = {
tags: PropTypes.objectOf(tagPropTypes),
}),
),
+
+ /** Holds data related to Money Request view state, rather than the underlying Money Request data. */
+ iou: iouPropTypes,
};
const defaultProps = {
report: {},
policyTags: {},
+ iou: iouDefaultProps,
};
-function MoneyRequestTagPage({route, report, policyTags}) {
+function MoneyRequestTagPage({route, report, policyTags, iou}) {
const {translate} = useLocalize();
const iouType = lodashGet(route, 'params.iouType', '');
@@ -55,10 +61,19 @@ function MoneyRequestTagPage({route, report, policyTags}) {
// Fetches the first tag list of the policy
const tagListKey = _.first(_.keys(policyTags));
const tagList = lodashGet(policyTags, tagListKey, {});
- const tagListName = lodashGet(tagList, 'name', '');
+ const tagListName = lodashGet(tagList, 'name', translate('common.tag'));
const navigateBack = () => {
- Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, lodashGet(report, 'reportID', '')));
+ Navigation.goBack(ROUTES.getMoneyRequestConfirmationRoute(iouType, report.reportID));
+ };
+
+ const updateTag = (selectedTag) => {
+ if (selectedTag.searchText === iou.tag) {
+ IOU.resetMoneyRequestTag();
+ } else {
+ IOU.setMoneyRequestTag(selectedTag.searchText);
+ }
+ navigateBack();
};
return (
@@ -67,15 +82,15 @@ function MoneyRequestTagPage({route, report, policyTags}) {
shouldEnableMaxHeight
>
- {translate('iou.tagSelection', {tagListName} || translate('common.tag'))}
+ {translate('iou.tagSelection', {tagName: tagListName})}
);
@@ -87,16 +102,13 @@ MoneyRequestTagPage.defaultProps = defaultProps;
export default compose(
withOnyx({
+ report: {
+ key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID')}`,
+ },
iou: {
key: ONYXKEYS.IOU,
},
}),
- withOnyx({
- report: {
- // Fetch report ID from IOU participants if no report ID is set in route
- key: ({route, iou}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '') || lodashGet(iou, 'participants.0.reportID', '')}`,
- },
- }),
withOnyx({
policyTags: {
key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`,
diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js
index 3f5672c3d33d..eb6e2328afd2 100644
--- a/src/pages/iou/ReceiptSelector/index.js
+++ b/src/pages/iou/ReceiptSelector/index.js
@@ -1,6 +1,7 @@
import {View, Text, PixelRatio} from 'react-native';
import React, {useContext, useState} from 'react';
import lodashGet from 'lodash/get';
+import _ from 'underscore';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import * as IOU from '../../../libs/actions/IOU';
@@ -15,21 +16,14 @@ import ReceiptDropUI from '../ReceiptDropUI';
import AttachmentPicker from '../../../components/AttachmentPicker';
import ConfirmModal from '../../../components/ConfirmModal';
import ONYXKEYS from '../../../ONYXKEYS';
-import Receipt from '../../../libs/actions/Receipt';
import useWindowDimensions from '../../../hooks/useWindowDimensions';
import useLocalize from '../../../hooks/useLocalize';
import {DragAndDropContext} from '../../../components/DragAndDrop/Provider';
-import * as ReceiptUtils from '../../../libs/ReceiptUtils';
import {iouPropTypes, iouDefaultProps} from '../propTypes';
+import * as FileUtils from '../../../libs/fileDownload/FileUtils';
+import Navigation from '../../../libs/Navigation/Navigation';
const propTypes = {
- /** Information shown to the user when a receipt is not valid */
- receiptModal: PropTypes.shape({
- isAttachmentInvalid: PropTypes.bool,
- attachmentInvalidReasonTitle: PropTypes.string,
- attachmentInvalidReason: PropTypes.string,
- }),
-
/** The report on which the request is initiated on */
report: reportPropTypes,
@@ -47,29 +41,64 @@ const propTypes = {
/** Holds data related to Money Request view state, rather than the underlying Money Request data. */
iou: iouPropTypes,
+
+ /** The id of the transaction we're editing */
+ transactionID: PropTypes.string,
};
const defaultProps = {
- receiptModal: {
- isAttachmentInvalid: false,
- attachmentInvalidReasonTitle: '',
- attachmentInvalidReason: '',
- },
report: {},
iou: iouDefaultProps,
+ transactionID: '',
};
function ReceiptSelector(props) {
const reportID = lodashGet(props.route, 'params.reportID', '');
const iouType = lodashGet(props.route, 'params.iouType', '');
- const isAttachmentInvalid = lodashGet(props.receiptModal, 'isAttachmentInvalid', false);
- const attachmentInvalidReasonTitle = lodashGet(props.receiptModal, 'attachmentInvalidReasonTitle', '');
- const attachmentInvalidReason = lodashGet(props.receiptModal, 'attachmentInvalidReason', '');
+ const [isAttachmentInvalid, setIsAttachmentInvalid] = useState(false);
+ const [attachmentInvalidReasonTitle, setAttachmentInvalidReasonTitle] = useState('');
+ const [attachmentInvalidReason, setAttachmentValidReason] = useState('');
const [receiptImageTopPosition, setReceiptImageTopPosition] = useState(0);
const {isSmallScreenWidth} = useWindowDimensions();
const {translate} = useLocalize();
const {isDraggingOver} = useContext(DragAndDropContext);
+ const hideReciptModal = () => {
+ setIsAttachmentInvalid(false);
+ };
+
+ /**
+ * Sets the upload receipt error modal content when an invalid receipt is uploaded
+ * @param {*} isInvalid
+ * @param {*} title
+ * @param {*} reason
+ */
+ const setUploadReceiptError = (isInvalid, title, reason) => {
+ setIsAttachmentInvalid(isInvalid);
+ setAttachmentInvalidReasonTitle(title);
+ setAttachmentValidReason(reason);
+ };
+
+ function validateReceipt(file) {
+ const {fileExtension} = FileUtils.splitExtensionFromFileName(lodashGet(file, 'name', ''));
+ if (_.contains(CONST.API_ATTACHMENT_VALIDATIONS.UNALLOWED_EXTENSIONS, fileExtension.toLowerCase())) {
+ setUploadReceiptError(true, 'attachmentPicker.wrongFileType', 'attachmentPicker.notAllowedExtension');
+ return false;
+ }
+
+ if (lodashGet(file, 'size', 0) > CONST.API_ATTACHMENT_VALIDATIONS.MAX_SIZE) {
+ setUploadReceiptError(true, 'attachmentPicker.attachmentTooLarge', 'attachmentPicker.sizeExceeded');
+ return false;
+ }
+
+ if (lodashGet(file, 'size', 0) < CONST.API_ATTACHMENT_VALIDATIONS.MIN_SIZE) {
+ setUploadReceiptError(true, 'attachmentPicker.attachmentTooSmall', 'attachmentPicker.sizeNotMet');
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Sets the Receipt objects and navigates the user to the next page
* @param {Object} file
@@ -77,12 +106,19 @@ function ReceiptSelector(props) {
* @param {Object} report
*/
const setReceiptAndNavigate = (file, iou, report) => {
- if (!ReceiptUtils.validateReceipt(file)) {
+ if (!validateReceipt(file)) {
return;
}
const filePath = URL.createObjectURL(file);
IOU.setMoneyRequestReceipt(filePath, file.name);
+
+ if (props.transactionID) {
+ IOU.replaceReceipt(props.transactionID, file, filePath);
+ Navigation.dismissModal();
+ return;
+ }
+
IOU.navigateToNextPage(iou, iouType, reportID, report);
};
@@ -142,8 +178,8 @@ function ReceiptSelector(props) {
/>
`${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`,
},
diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js
index 4ff32d940c9f..36f883ad08e5 100644
--- a/src/pages/iou/ReceiptSelector/index.native.js
+++ b/src/pages/iou/ReceiptSelector/index.native.js
@@ -23,6 +23,8 @@ import Log from '../../../libs/Log';
import * as CameraPermission from './CameraPermission';
import {iouPropTypes, iouDefaultProps} from '../propTypes';
import NavigationAwareCamera from './NavigationAwareCamera';
+import Navigation from '../../../libs/Navigation/Navigation';
+import * as FileUtils from '../../../libs/fileDownload/FileUtils';
const propTypes = {
/** React Navigation route */
@@ -42,11 +44,15 @@ const propTypes = {
/** Holds data related to Money Request view state, rather than the underlying Money Request data. */
iou: iouPropTypes,
+
+ /** The id of the transaction we're editing */
+ transactionID: PropTypes.string,
};
const defaultProps = {
report: {},
iou: iouDefaultProps,
+ transactionID: '',
};
/**
@@ -74,7 +80,7 @@ function getImagePickerOptions(type) {
};
}
-function ReceiptSelector(props) {
+function ReceiptSelector({route, report, iou, transactionID}) {
const devices = useCameraDevices('wide-angle-camera');
const device = devices.back;
@@ -84,9 +90,9 @@ function ReceiptSelector(props) {
const isAndroidBlockedPermissionRef = useRef(false);
const appState = useRef(AppState.currentState);
- const iouType = lodashGet(props.route, 'params.iouType', '');
- const reportID = lodashGet(props.route, 'params.reportID', '');
- const pageIndex = lodashGet(props.route, 'params.pageIndex', 1);
+ const iouType = lodashGet(route, 'params.iouType', '');
+ const reportID = lodashGet(route, 'params.reportID', '');
+ const pageIndex = lodashGet(route, 'params.pageIndex', 1);
const {translate} = useLocalize();
@@ -195,14 +201,25 @@ function ReceiptSelector(props) {
flash: flash ? 'on' : 'off',
})
.then((photo) => {
- IOU.setMoneyRequestReceipt(`file://${photo.path}`, photo.path);
- IOU.navigateToNextPage(props.iou, iouType, reportID, props.report);
+ const filePath = `file://${photo.path}`;
+ IOU.setMoneyRequestReceipt(filePath, photo.path);
+
+ if (transactionID) {
+ FileUtils.readFileAsync(filePath, photo.path).then((receipt) => {
+ IOU.replaceReceipt(transactionID, receipt, filePath);
+ });
+
+ Navigation.dismissModal();
+ return;
+ }
+
+ IOU.navigateToNextPage(iou, iouType, reportID, report);
})
.catch((error) => {
showCameraAlert();
Log.warn('Error taking photo', error);
});
- }, [flash, iouType, props.iou, props.report, reportID, translate]);
+ }, [flash, iouType, iou, report, reportID, translate, transactionID]);
CameraPermission.getCameraPermissionStatus().then((permissionStatus) => {
setPermissions(permissionStatus);
@@ -260,8 +277,18 @@ function ReceiptSelector(props) {
onPress={() => {
showImagePicker(launchImageLibrary)
.then((receiptImage) => {
- IOU.setMoneyRequestReceipt(receiptImage[0].uri, receiptImage[0].fileName);
- IOU.navigateToNextPage(props.iou, iouType, reportID, props.report);
+ const filePath = receiptImage[0].uri;
+ IOU.setMoneyRequestReceipt(filePath, receiptImage[0].fileName);
+
+ if (transactionID) {
+ FileUtils.readFileAsync(filePath, receiptImage[0].fileName).then((receipt) => {
+ IOU.replaceReceipt(transactionID, receipt, filePath);
+ });
+ Navigation.dismissModal();
+ return;
+ }
+
+ IOU.navigateToNextPage(iou, iouType, reportID, report);
})
.catch(() => {
Log.info('User did not select an image from gallery');
diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js
index b11b16fa3c1b..0107b041abf4 100644
--- a/src/pages/iou/SplitBillDetailsPage.js
+++ b/src/pages/iou/SplitBillDetailsPage.js
@@ -61,14 +61,11 @@ function SplitBillDetailsPage(props) {
let participants;
if (ReportUtils.isPolicyExpenseChat(props.report)) {
participants = [
- ...OptionsListUtils.getParticipantsOptions([{accountID: participantAccountIDs[0], selected: true}], props.personalDetails),
- ...OptionsListUtils.getPolicyExpenseReportOptions({...props.report, selected: true}),
+ OptionsListUtils.getParticipantsOption({accountID: participantAccountIDs[0], selected: true}, props.personalDetails),
+ OptionsListUtils.getPolicyExpenseReportOption({...props.report, selected: true}),
];
} else {
- participants = OptionsListUtils.getParticipantsOptions(
- _.map(participantAccountIDs, (accountID) => ({accountID, selected: true})),
- props.personalDetails,
- );
+ participants = _.map(participantAccountIDs, (accountID) => OptionsListUtils.getParticipantsOption({accountID, selected: true}, props.personalDetails));
}
const payeePersonalDetails = props.personalDetails[reportAction.actorAccountID];
const participantsExcludingPayee = _.filter(participants, (participant) => participant.accountID !== reportAction.actorAccountID);
diff --git a/src/pages/iou/WaypointEditor.js b/src/pages/iou/WaypointEditor.js
index 68e85a34746d..e34730acccea 100644
--- a/src/pages/iou/WaypointEditor.js
+++ b/src/pages/iou/WaypointEditor.js
@@ -23,6 +23,7 @@ import * as Transaction from '../../libs/actions/Transaction';
import * as ValidationUtils from '../../libs/ValidationUtils';
import ROUTES from '../../ROUTES';
import transactionPropTypes from '../../components/transactionPropTypes';
+import * as ErrorUtils from '../../libs/ErrorUtils';
const propTypes = {
/** The transactionID of the IOU */
@@ -104,18 +105,28 @@ function WaypointEditor({transactionID, route: {params: {iouType = '', waypointI
const errors = {};
const waypointValue = values[`waypoint${waypointIndex}`] || '';
if (isOffline && waypointValue !== '' && !ValidationUtils.isValidAddress(waypointValue)) {
- errors[`waypoint${waypointIndex}`] = 'bankAccount.error.address';
+ ErrorUtils.addErrorMessage(errors, `waypoint${waypointIndex}`, 'bankAccount.error.address');
}
// If the user is online and they are trying to save a value without using the autocomplete, show an error message instructing them to use a selected address instead.
// That enables us to save the address with coordinates when it is selected
if (!isOffline && waypointValue !== '' && waypointAddress !== waypointValue) {
- errors[`waypoint${waypointIndex}`] = 'distance.errors.selectSuggestedAddress';
+ ErrorUtils.addErrorMessage(errors, `waypoint${waypointIndex}`, 'distance.errors.selectSuggestedAddress');
}
return errors;
};
+ const saveWaypoint = (waypoint) => {
+ if (parsedWaypointIndex < _.size(allWaypoints)) {
+ Transaction.saveWaypoint(transactionID, waypointIndex, waypoint);
+ } else {
+ const finishWaypoint = lodashGet(allWaypoints, `waypoint${_.size(allWaypoints) - 1}`, {});
+ Transaction.saveWaypoint(transactionID, waypointIndex, finishWaypoint);
+ Transaction.saveWaypoint(transactionID, waypointIndex - 1, waypoint);
+ }
+ };
+
const onSubmit = (values) => {
const waypointValue = values[`waypoint${waypointIndex}`] || '';
@@ -132,8 +143,7 @@ function WaypointEditor({transactionID, route: {params: {iouType = '', waypointI
lng: null,
address: waypointValue,
};
-
- Transaction.saveWaypoint(transactionID, waypointIndex, waypoint);
+ saveWaypoint(waypoint);
}
// Other flows will be handled by selecting a waypoint with selectWaypoint as this is mainly for the offline flow
@@ -152,8 +162,7 @@ function WaypointEditor({transactionID, route: {params: {iouType = '', waypointI
lng: values.lng,
address: values.address,
};
-
- Transaction.saveWaypoint(transactionID, waypointIndex, waypoint);
+ saveWaypoint(waypoint);
Navigation.goBack(ROUTES.getMoneyRequestDistanceTabRoute(iouType));
};
@@ -163,7 +172,7 @@ function WaypointEditor({transactionID, route: {params: {iouType = '', waypointI
onEntryTransitionEnd={() => textInput.current && textInput.current.focus()}
shouldEnableMaxHeight
>
- waypointCount - 1) && isFocused}>
+ waypointCount) && isFocused}>
(textInput.current = e)}
- hint={!isOffline ? translate('distance.errors.selectSuggestedAddress') : ''}
+ hint={!isOffline ? 'distance.errors.selectSuggestedAddress' : ''}
containerStyles={[styles.mt4]}
label={translate('distance.address')}
defaultValue={waypointAddress}
diff --git a/src/pages/iou/steps/MoneyRequestAmountForm.js b/src/pages/iou/steps/MoneyRequestAmountForm.js
index 1ea0b002b235..e08fd5bde881 100644
--- a/src/pages/iou/steps/MoneyRequestAmountForm.js
+++ b/src/pages/iou/steps/MoneyRequestAmountForm.js
@@ -12,6 +12,7 @@ import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
import TextInputWithCurrencySymbol from '../../../components/TextInputWithCurrencySymbol';
import useLocalize from '../../../hooks/useLocalize';
import CONST from '../../../CONST';
+import FormHelpMessage from '../../../components/FormHelpMessage';
import refPropTypes from '../../../components/refPropTypes';
import getOperatingSystem from '../../../libs/getOperatingSystem';
import * as Browser from '../../../libs/Browser';
@@ -57,6 +58,8 @@ const getNewSelection = (oldSelection, prevLength, newLength) => {
return {start: cursorPosition, end: cursorPosition};
};
+const isAmountValid = (amount) => !amount.length || parseFloat(amount) < 0.01;
+
const AMOUNT_VIEW_ID = 'amountView';
const NUM_PAD_CONTAINER_VIEW_ID = 'numPadContainerView';
const NUM_PAD_VIEW_ID = 'numPadView';
@@ -70,6 +73,9 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
const selectedAmountAsString = amount ? CurrencyUtils.convertToFrontendAmount(amount).toString() : '';
const [currentAmount, setCurrentAmount] = useState(selectedAmountAsString);
+ const [isInvalidAmount, setIsInvalidAmount] = useState(isAmountValid(selectedAmountAsString));
+ const [firstPress, setFirstPress] = useState(false);
+ const [formError, setFormError] = useState('');
const [shouldUpdateSelection, setShouldUpdateSelection] = useState(true);
const [selection, setSelection] = useState({
@@ -127,6 +133,9 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
setSelection((prevSelection) => ({...prevSelection}));
return;
}
+ const checkInvalidAmount = isAmountValid(newAmountWithoutSpaces);
+ setIsInvalidAmount(checkInvalidAmount);
+ setFormError(checkInvalidAmount ? 'iou.error.invalidAmount' : '');
setCurrentAmount((prevAmount) => {
const strippedAmount = MoneyRequestUtils.stripCommaFromAmount(newAmountWithoutSpaces);
const isForwardDelete = prevAmount.length > strippedAmount.length && forwardDeletePressedRef.current;
@@ -177,8 +186,13 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
* Submit amount and navigate to a proper page
*/
const submitAndNavigateToNextPage = useCallback(() => {
+ if (isInvalidAmount) {
+ setFirstPress(true);
+ setFormError('iou.error.invalidAmount');
+ return;
+ }
onSubmitButtonPress(currentAmount);
- }, [onSubmitButtonPress, currentAmount]);
+ }, [onSubmitButtonPress, currentAmount, isInvalidAmount]);
/**
* Input handler to check for a forward-delete key (or keyboard shortcut) press.
@@ -231,9 +245,16 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
onKeyPress={textInputKeyPress}
/>
+ {!_.isEmpty(formError) && firstPress && (
+
+ )}
onMouseDown(event, [NUM_PAD_CONTAINER_VIEW_ID, NUM_PAD_VIEW_ID])}
- style={[styles.w100, styles.justifyContentEnd, styles.pageWrapper]}
+ style={[styles.w100, styles.justifyContentEnd, styles.pageWrapper, styles.pt0]}
nativeID={NUM_PAD_CONTAINER_VIEW_ID}
>
{DeviceCapabilities.canUseTouchScreen() ? (
@@ -249,7 +270,6 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
style={[styles.w100, styles.mt5]}
onPress={submitAndNavigateToNextPage}
pressOnEnter
- isDisabled={!currentAmount.length || parseFloat(currentAmount) < 0.01}
text={buttonText}
/>
diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js
index 38a5b9c82c07..93ee2c7f8aac 100644
--- a/src/pages/iou/steps/MoneyRequestConfirmPage.js
+++ b/src/pages/iou/steps/MoneyRequestConfirmPage.js
@@ -23,6 +23,7 @@ import reportPropTypes from '../../reportPropTypes';
import personalDetailsPropType from '../../personalDetailsPropType';
import * as FileUtils from '../../../libs/fileDownload/FileUtils';
import * as Policy from '../../../libs/actions/Policy';
+import useNetwork from '../../../hooks/useNetwork';
import useWindowDimensions from '../../../hooks/useWindowDimensions';
import * as StyleUtils from '../../../styles/StyleUtils';
import {iouPropTypes, iouDefaultProps} from '../propTypes';
@@ -59,6 +60,7 @@ const defaultProps = {
};
function MoneyRequestConfirmPage(props) {
+ const {isOffline} = useNetwork();
const {windowHeight} = useWindowDimensions();
const prevMoneyRequestId = useRef(props.iou.id);
const iouType = useRef(lodashGet(props.route, 'params.iouType', ''));
@@ -66,9 +68,10 @@ function MoneyRequestConfirmPage(props) {
const reportID = useRef(lodashGet(props.route, 'params.reportID', ''));
const participants = useMemo(
() =>
- lodashGet(props.iou.participants, [0, 'isPolicyExpenseChat'], false)
- ? OptionsListUtils.getPolicyExpenseReportOptions(props.iou.participants[0])
- : OptionsListUtils.getParticipantsOptions(props.iou.participants, props.personalDetails),
+ _.map(props.iou.participants, (participant) => {
+ const isPolicyExpenseChat = lodashGet(participant, 'isPolicyExpenseChat', false);
+ return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, props.personalDetails);
+ }),
[props.iou.participants, props.personalDetails],
);
@@ -77,8 +80,11 @@ function MoneyRequestConfirmPage(props) {
if (policyExpenseChat) {
Policy.openDraftWorkspaceRequest(policyExpenseChat.policyID);
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ // Verification to reset billable with a default value, when value in IOU was changed
+ if (typeof props.iou.billable !== 'boolean') {
+ IOU.setMoneyRequestBillable(lodashGet(props.policy, 'defaultBillable', false));
+ }
+ }, [isOffline, participants, props.iou.billable, props.policy]);
useEffect(() => {
// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
@@ -135,6 +141,8 @@ function MoneyRequestConfirmPage(props) {
trimmedComment,
receipt,
props.iou.category,
+ props.iou.tag,
+ props.iou.billable,
);
},
[
@@ -146,6 +154,8 @@ function MoneyRequestConfirmPage(props) {
props.currentUserPersonalDetails.login,
props.currentUserPersonalDetails.accountID,
props.iou.category,
+ props.iou.tag,
+ props.iou.billable,
],
);
@@ -162,12 +172,13 @@ function MoneyRequestConfirmPage(props) {
props.iou.created,
props.iou.transactionID,
props.iou.category,
+ props.iou.tag,
props.iou.amount,
props.iou.currency,
props.iou.merchant,
);
},
- [props.report, props.iou.created, props.iou.transactionID, props.iou.category, props.iou.amount, props.iou.currency, props.iou.merchant],
+ [props.report, props.iou.created, props.iou.transactionID, props.iou.category, props.iou.tag, props.iou.amount, props.iou.currency, props.iou.merchant],
);
const createTransaction = useCallback(
@@ -246,11 +257,6 @@ function MoneyRequestConfirmPage(props) {
return;
}
- if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.PAYPAL_ME) {
- IOU.sendMoneyViaPaypal(props.report, props.iou.amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant);
- return;
- }
-
if (paymentMethodType === CONST.IOU.PAYMENT_TYPE.EXPENSIFY) {
IOU.sendMoneyWithWallet(props.report, props.iou.amount, currency, trimmedComment, props.currentUserPersonalDetails.accountID, participant);
}
@@ -295,6 +301,8 @@ function MoneyRequestConfirmPage(props) {
iouAmount={props.iou.amount}
iouComment={props.iou.comment}
iouCurrencyCode={props.iou.currency}
+ iouIsBillable={props.iou.billable}
+ onToggleBillable={IOU.setMoneyRequestBillable}
iouCategory={props.iou.category}
iouTag={props.iou.tag}
onConfirm={createTransaction}
@@ -364,4 +372,9 @@ export default compose(
key: `${ONYXKEYS.COLLECTION.SELECTED_TAB}${CONST.TAB.RECEIPT_TAB_ID}`,
},
}),
+ withOnyx({
+ policy: {
+ key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report.policyID}`,
+ },
+ }),
)(MoneyRequestConfirmPage);
diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js
index 1d9f12a9cdbb..cb9f4cdd9b7f 100644
--- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js
+++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js
@@ -50,6 +50,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
const iouType = useRef(lodashGet(route, 'params.iouType', ''));
const reportID = useRef(lodashGet(route, 'params.reportID', ''));
const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType.current, selectedTab);
+ const isScanRequest = MoneyRequestUtils.isScanRequest(selectedTab);
const isSplitRequest = iou.id === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT;
const [headerTitle, setHeaderTitle] = useState();
@@ -117,6 +118,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
iouType={iouType.current}
isDistanceRequest={isDistanceRequest}
+ isScanRequest={isScanRequest}
/>
)}
diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
index 9ff787ebe21b..a8da1b4ec9ed 100755
--- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
+++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
@@ -3,6 +3,7 @@ import {View} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
+import lodashGet from 'lodash/get';
import ONYXKEYS from '../../../../ONYXKEYS';
import styles from '../../../../styles/styles';
import OptionsSelector from '../../../../components/OptionsSelector';
@@ -58,6 +59,9 @@ const propTypes = {
/** Whether the money request is a distance request or not */
isDistanceRequest: PropTypes.bool,
+ /** Whether the money request is a scan request or not */
+ isScanRequest: PropTypes.bool,
+
...withLocalizePropTypes,
};
@@ -69,6 +73,7 @@ const defaultProps = {
reports: {},
betas: [],
isDistanceRequest: false,
+ isScanRequest: false,
};
function MoneyRequestParticipantsSelector({
@@ -84,6 +89,7 @@ function MoneyRequestParticipantsSelector({
safeAreaPaddingBottomStyle,
iouType,
isDistanceRequest,
+ isScanRequest,
}) {
const [searchTerm, setSearchTerm] = useState('');
const [newChatOptions, setNewChatOptions] = useState({
@@ -105,7 +111,10 @@ function MoneyRequestParticipantsSelector({
newSections.push({
title: undefined,
- data: OptionsListUtils.getParticipantsOptions(participants, personalDetails),
+ data: _.map(participants, (participant) => {
+ const isPolicyExpenseChat = lodashGet(participant, 'isPolicyExpenseChat', false);
+ return isPolicyExpenseChat ? OptionsListUtils.getPolicyExpenseReportOption(participant) : OptionsListUtils.getParticipantsOption(participant, personalDetails);
+ }),
shouldShow: true,
indexOffset,
});
@@ -149,7 +158,9 @@ function MoneyRequestParticipantsSelector({
* @param {Object} option
*/
const addSingleParticipant = (option) => {
- onAddParticipants([{accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true}]);
+ onAddParticipants([
+ {accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true, searchText: option.searchText},
+ ]);
navigateToRequest();
};
@@ -159,19 +170,39 @@ function MoneyRequestParticipantsSelector({
*/
const addParticipantToSelection = useCallback(
(option) => {
- const isOptionInList = _.some(participants, (selectedOption) => selectedOption.accountID === option.accountID);
-
+ const isOptionSelected = (selectedOption) => {
+ if (selectedOption.accountID && selectedOption.accountID === option.accountID) {
+ return true;
+ }
+
+ if (selectedOption.reportID && selectedOption.reportID === option.reportID) {
+ return true;
+ }
+
+ return false;
+ };
+ const isOptionInList = _.some(participants, isOptionSelected);
let newSelectedOptions;
if (isOptionInList) {
- newSelectedOptions = _.reject(participants, (selectedOption) => selectedOption.accountID === option.accountID);
+ newSelectedOptions = _.reject(participants, isOptionSelected);
} else {
- newSelectedOptions = [...participants, {accountID: option.accountID, login: option.login, selected: true}];
+ newSelectedOptions = [
+ ...participants,
+ {
+ accountID: option.accountID,
+ login: option.login,
+ isPolicyExpenseChat: option.isPolicyExpenseChat,
+ reportID: option.reportID,
+ selected: true,
+ searchText: option.searchText,
+ },
+ ];
}
onAddParticipants(newSelectedOptions);
- const chatOptions = OptionsListUtils.getNewChatOptions(
+ const chatOptions = OptionsListUtils.getFilteredOptions(
reports,
personalDetails,
betas,
@@ -199,13 +230,14 @@ function MoneyRequestParticipantsSelector({
const headerMessage = OptionsListUtils.getHeaderMessage(
newChatOptions.personalDetails.length + newChatOptions.recentReports.length !== 0,
Boolean(newChatOptions.userToInvite),
- searchTerm,
+ searchTerm.trim(),
maxParticipantsReached,
+ _.some(participants, (participant) => participant.searchText.toLowerCase().includes(searchTerm.trim().toLowerCase())),
);
const isOptionsDataReady = ReportUtils.isReportDataReady() && OptionsListUtils.isPersonalDetailsReady(personalDetails);
useEffect(() => {
- const chatOptions = OptionsListUtils.getNewChatOptions(
+ const chatOptions = OptionsListUtils.getFilteredOptions(
reports,
personalDetails,
betas,
@@ -227,10 +259,17 @@ function MoneyRequestParticipantsSelector({
});
}, [betas, reports, participants, personalDetails, translate, searchTerm, setNewChatOptions, iouType, isDistanceRequest]);
+ // Right now you can't split a request with a workspace and other additional participants
+ // This is getting properly fixed in https://github.com/Expensify/App/issues/27508, but as a stop-gap to prevent
+ // the app from crashing on native when you try to do this, we'll going to hide the button if you have a workspace and other participants
+ const hasPolicyExpenseChatParticipant = _.some(participants, (participant) => participant.isPolicyExpenseChat);
+ const shouldShowConfirmButton = !(participants.length > 1 && hasPolicyExpenseChatParticipant);
+ const isAllowedToSplit = !isDistanceRequest && !isScanRequest;
+
return (
0 ? safeAreaPaddingBottomStyle : {}]}>
{
// Component may not be initialized due to navigation transitions
@@ -99,12 +99,6 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) {
// Because we use Onyx to store IOU info, when we try to make two different money requests from different tabs,
// it can result in an IOU sent with improper values. In such cases we want to reset the flow and redirect the user to the first step of the IOU.
useEffect(() => {
- const moneyRequestID = `${iouType}${reportID}`;
- const shouldReset = iou.id !== moneyRequestID;
- if (shouldReset) {
- IOU.resetMoneyRequestInfo(moneyRequestID);
- }
-
if (isEditing) {
// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
if (prevMoneyRequestID.current !== iou.id) {
@@ -115,6 +109,11 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) {
Navigation.goBack(ROUTES.getMoneyRequestRoute(iouType, reportID), true);
return;
}
+ const moneyRequestID = `${iouType}${reportID}`;
+ const shouldReset = iou.id !== moneyRequestID;
+ if (shouldReset) {
+ IOU.resetMoneyRequestInfo(moneyRequestID);
+ }
if (!isDistanceRequestTab && (_.isEmpty(iou.participantAccountIDs) || iou.amount === 0 || shouldReset)) {
Navigation.goBack(ROUTES.getMoneyRequestRoute(iouType, reportID), true);
@@ -127,7 +126,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) {
}, [iou.participantAccountIDs, iou.amount, iou.id, isEditing, iouType, reportID, isDistanceRequestTab]);
const navigateBack = () => {
- Navigation.goBack(isEditing ? ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID) : null);
+ Navigation.goBack(isEditing ? ROUTES.getMoneyRequestConfirmationRoute(iouType, reportID) : ROUTES.HOME);
};
const navigateToCurrencySelectionPage = () => {
diff --git a/src/pages/settings/InitialSettingsPage.js b/src/pages/settings/InitialSettingsPage.js
index a67e7cbc122e..d10779210b09 100755
--- a/src/pages/settings/InitialSettingsPage.js
+++ b/src/pages/settings/InitialSettingsPage.js
@@ -1,6 +1,6 @@
import lodashGet from 'lodash/get';
import React, {useState, useEffect, useRef, useMemo, useCallback} from 'react';
-import {View, ScrollView} from 'react-native';
+import {View} from 'react-native';
import PropTypes from 'prop-types';
import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
@@ -12,11 +12,11 @@ import * as Session from '../../libs/actions/Session';
import ONYXKEYS from '../../ONYXKEYS';
import Tooltip from '../../components/Tooltip';
import Avatar from '../../components/Avatar';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
import Navigation from '../../libs/Navigation/Navigation';
import * as Expensicons from '../../components/Icon/Expensicons';
-import ScreenWrapper from '../../components/ScreenWrapper';
import MenuItem from '../../components/MenuItem';
+import themeColors from '../../styles/themes/default';
+import SCREENS from '../../SCREENS';
import ROUTES from '../../ROUTES';
import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
import compose from '../../libs/compose';
@@ -43,6 +43,7 @@ import PressableWithoutFeedback from '../../components/Pressable/PressableWithou
import useLocalize from '../../hooks/useLocalize';
import useSingleExecution from '../../hooks/useSingleExecution';
import useWaitForNavigation from '../../hooks/useWaitForNavigation';
+import HeaderPageLayout from '../../components/HeaderPageLayout';
const propTypes = {
/* Onyx Props */
@@ -326,79 +327,80 @@ function InitialSettingsPage(props) {
if (_.isEmpty(props.currentUserPersonalDetails)) {
return null;
}
-
- return (
-
- {({safeAreaPaddingBottomStyle}) => (
+ const headerContent = (
+
+ {_.isEmpty(props.currentUserPersonalDetails) || _.isUndefined(props.currentUserPersonalDetails.displayName) ? (
+
+ ) : (
<>
-
-
+
+
+
+
+
+
+
-
- {_.isEmpty(props.currentUserPersonalDetails) || _.isUndefined(props.currentUserPersonalDetails.displayName) ? (
-
- ) : (
-
-
-
-
-
-
-
-
-
-
-
- {props.currentUserPersonalDetails.displayName ? props.currentUserPersonalDetails.displayName : props.formatPhoneNumber(props.session.email)}
-
-
-
- {Boolean(props.currentUserPersonalDetails.displayName) && (
-
- {props.formatPhoneNumber(props.session.email)}
-
- )}
-
- )}
- {getMenuItems}
-
- signOut(true)}
- onCancel={() => toggleSignoutConfirmModal(false)}
- />
-
-
+
+
+ {props.currentUserPersonalDetails.displayName ? props.currentUserPersonalDetails.displayName : props.formatPhoneNumber(props.session.email)}
+
+
+
+ {Boolean(props.currentUserPersonalDetails.displayName) && (
+
+ {props.formatPhoneNumber(props.session.email)}
+
+ )}
>
)}
-
+
+ );
+
+ return (
+
+
+ {getMenuItems}
+ signOut(true)}
+ onCancel={() => toggleSignoutConfirmModal(false)}
+ />
+
+
);
}
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index f178b25fd0fb..807bd73cecc1 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -2,10 +2,9 @@ import React, {useMemo, useCallback, useEffect} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
-import moment from 'moment';
import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails';
import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import StaticHeaderPageLayout from '../../../../components/StaticHeaderPageLayout';
+import HeaderPageLayout from '../../../../components/HeaderPageLayout';
import * as Expensicons from '../../../../components/Icon/Expensicons';
import withLocalize from '../../../../components/withLocalize';
import MenuItem from '../../../../components/MenuItem';
@@ -20,6 +19,7 @@ import styles from '../../../../styles/styles';
import compose from '../../../../libs/compose';
import ONYXKEYS from '../../../../ONYXKEYS';
import ROUTES from '../../../../ROUTES';
+import SCREENS from '../../../../SCREENS';
const propTypes = {
...withCurrentUserPersonalDetailsPropTypes,
@@ -44,8 +44,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
const navigateBackToSettingsPage = useCallback(() => Navigation.goBack(ROUTES.SETTINGS_PROFILE, false, true), []);
const updateStatus = useCallback(() => {
- const endOfDay = moment().endOf('day').format('YYYY-MM-DD HH:mm:ss');
- User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji, clearAfter: endOfDay});
+ User.updateCustomStatus({text: defaultText, emojiCode: defaultEmoji});
User.clearDraftCustomStatus();
Navigation.goBack(ROUTES.SETTINGS_PROFILE);
@@ -65,11 +64,17 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
useEffect(() => () => User.clearDraftCustomStatus(), []);
return (
-
+ }
+ headerContainerStyles={[styles.staticHeaderImage]}
+ backgroundColor={themeColors.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.STATUS]}
footer={footerComponent}
>
@@ -93,7 +98,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) {
wrapperStyle={[styles.cardMenuItem]}
/>
)}
-
+
);
}
diff --git a/src/pages/settings/Profile/LoungeAccessPage.js b/src/pages/settings/Profile/LoungeAccessPage.js
index ce047bd9ccae..c322c8e426f3 100644
--- a/src/pages/settings/Profile/LoungeAccessPage.js
+++ b/src/pages/settings/Profile/LoungeAccessPage.js
@@ -66,7 +66,7 @@ function LoungeAccessPage(props) {
const overlayContent = () => (
diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js
index b0cbe7c9cc32..1864ba60524c 100755
--- a/src/pages/settings/Profile/ProfilePage.js
+++ b/src/pages/settings/Profile/ProfilePage.js
@@ -65,6 +65,8 @@ function ProfilePage(props) {
};
const currentUserDetails = props.currentUserPersonalDetails || {};
const contactMethodBrickRoadIndicator = UserUtils.getLoginListBrickRoadIndicator(props.loginList);
+ const avatarURL = lodashGet(currentUserDetails, 'avatar', '');
+ const accountID = lodashGet(currentUserDetails, 'accountID', '');
const emojiCode = lodashGet(props, 'currentUserPersonalDetails.status.emojiCode', '');
const profileSettingsOptions = [
@@ -113,7 +115,7 @@ function ProfilePage(props) {
diff --git a/src/pages/settings/Security/SecuritySettingsPage.js b/src/pages/settings/Security/SecuritySettingsPage.js
index 7f08247557f4..293e488ede7a 100644
--- a/src/pages/settings/Security/SecuritySettingsPage.js
+++ b/src/pages/settings/Security/SecuritySettingsPage.js
@@ -5,6 +5,7 @@ import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
import Navigation from '../../../libs/Navigation/Navigation';
import ROUTES from '../../../ROUTES';
+import SCREENS from '../../../SCREENS';
import styles from '../../../styles/styles';
import * as Expensicons from '../../../components/Icon/Expensicons';
import themeColors from '../../../styles/themes/default';
@@ -54,7 +55,7 @@ function SecuritySettingsPage(props) {
shouldShowBackButton
shouldShowCloseButton
illustration={LottieAnimations.Safe}
- backgroundColor={themeColors.PAGE_BACKGROUND_COLORS[ROUTES.SETTINGS_SECURITY]}
+ backgroundColor={themeColors.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.SECURITY]}
>
diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js
index 52d7a9806f69..7aa7a8ab64c1 100644
--- a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js
+++ b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js
@@ -1,4 +1,4 @@
-import React, {useEffect} from 'react';
+import React, {useEffect, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
import {ActivityIndicator, View} from 'react-native';
import {ScrollView} from 'react-native-gesture-handler';
@@ -23,10 +23,12 @@ import useWindowDimensions from '../../../../../hooks/useWindowDimensions';
import StepWrapper from '../StepWrapper/StepWrapper';
import {defaultAccount, TwoFactorAuthPropTypes} from '../TwoFactorAuthPropTypes';
import * as TwoFactorAuthActions from '../../../../../libs/actions/TwoFactorAuthActions';
+import FormHelpMessage from '../../../../../components/FormHelpMessage';
function CodesStep({account = defaultAccount}) {
const {translate} = useLocalize();
const {isExtraSmallScreenWidth, isSmallScreenWidth} = useWindowDimensions();
+ const [error, setError] = useState('');
const {setStep} = useTwoFactorAuthContext();
@@ -83,6 +85,7 @@ function CodesStep({account = defaultAccount}) {
inline={false}
onPress={() => {
Clipboard.setString(account.recoveryCodes);
+ setError('');
TwoFactorAuthActions.setCodesAreCopied();
}}
styles={[styles.button, styles.buttonMedium, styles.twoFactorAuthCodesButton]}
@@ -93,6 +96,7 @@ function CodesStep({account = defaultAccount}) {
icon={Expensicons.Download}
onPress={() => {
localFileDownload('two-factor-auth-codes', account.recoveryCodes);
+ setError('');
TwoFactorAuthActions.setCodesAreCopied();
}}
inline={false}
@@ -106,11 +110,23 @@ function CodesStep({account = defaultAccount}) {
+ {!_.isEmpty(error) && (
+
+ )}
diff --git a/src/pages/settings/Wallet/AddPayPalMePage.js b/src/pages/settings/Wallet/AddPayPalMePage.js
deleted file mode 100644
index 38eae4d46bbc..000000000000
--- a/src/pages/settings/Wallet/AddPayPalMePage.js
+++ /dev/null
@@ -1,142 +0,0 @@
-import React, {useRef, useCallback} from 'react';
-import {View} from 'react-native';
-import _ from 'underscore';
-import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import CONST from '../../../CONST';
-import ROUTES from '../../../ROUTES';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import TextLink from '../../../components/TextLink';
-import Text from '../../../components/Text';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import Navigation from '../../../libs/Navigation/Navigation';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Form from '../../../components/Form';
-import Growl from '../../../libs/Growl';
-import TextInput from '../../../components/TextInput';
-import * as ValidationUtils from '../../../libs/ValidationUtils';
-import * as User from '../../../libs/actions/User';
-import Icon from '../../../components/Icon';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import variables from '../../../styles/variables';
-import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback';
-import paypalMeDataPropTypes from '../../../components/paypalMeDataPropTypes';
-import * as Link from '../../../libs/actions/Link';
-
-const propTypes = {
- /** Account details for PayPal.Me */
- payPalMeData: paypalMeDataPropTypes,
-
- ...withLocalizePropTypes,
-};
-
-const defaultProps = {
- payPalMeData: {},
-};
-
-const validate = (values) => {
- const requiredFields = ['payPalMeUsername'];
- const errors = ValidationUtils.getFieldRequiredErrors(values, requiredFields);
-
- if (values.payPalMeUsername && !ValidationUtils.isValidPaypalUsername(values.payPalMeUsername)) {
- errors.payPalMeUsername = 'addPayPalMePage.formatError';
- }
-
- return errors;
-};
-
-function AddPayPalMePage(props) {
- const payPalMeInput = useRef(null);
-
- const hasPaypalAccount = !_.isEmpty(props.payPalMeData);
-
- const growlMessageOnSave = props.translate(hasPaypalAccount ? 'addPayPalMePage.growlMessageOnUpdate' : 'addPayPalMePage.growlMessageOnSave');
-
- /**
- * Sets the payPalMe username and error data for the current user
- */
- const setPayPalMeData = useCallback(
- (values) => {
- User.addPaypalMeAddress(values.payPalMeUsername);
- Growl.show(growlMessageOnSave, CONST.GROWL.SUCCESS, 3000);
- Navigation.goBack(ROUTES.SETTINGS_WALLET);
- },
- [growlMessageOnSave],
- );
-
- return (
- payPalMeInput.current && payPalMeInput.current.focus()}
- >
- Navigation.goBack(ROUTES.SETTINGS_WALLET)}
- />
-
-
- );
-}
-
-AddPayPalMePage.propTypes = propTypes;
-AddPayPalMePage.defaultProps = defaultProps;
-AddPayPalMePage.displayName = 'AddPayPalMePage';
-
-export default compose(
- withLocalize,
- withOnyx({
- payPalMeData: {
- key: ONYXKEYS.PAYPAL,
- },
- }),
-)(AddPayPalMePage);
diff --git a/src/pages/settings/Wallet/PaymentMethodList.js b/src/pages/settings/Wallet/PaymentMethodList.js
index 94bcf9f87078..d757db370b05 100644
--- a/src/pages/settings/Wallet/PaymentMethodList.js
+++ b/src/pages/settings/Wallet/PaymentMethodList.js
@@ -16,7 +16,6 @@ import ONYXKEYS from '../../../ONYXKEYS';
import CONST from '../../../CONST';
import * as Expensicons from '../../../components/Icon/Expensicons';
import bankAccountPropTypes from '../../../components/bankAccountPropTypes';
-import paypalMeDataPropTypes from '../../../components/paypalMeDataPropTypes';
import cardPropTypes from '../../../components/cardPropTypes';
import * as PaymentUtils from '../../../libs/PaymentUtils';
import FormAlertWrapper from '../../../components/FormAlertWrapper';
@@ -28,9 +27,6 @@ const propTypes = {
/** What to do when a menu item is pressed */
onPress: PropTypes.func.isRequired,
- /** Account details for PayPal.Me */
- payPalMeData: paypalMeDataPropTypes,
-
/** List of bank accounts */
bankAccountList: PropTypes.objectOf(bankAccountPropTypes),
@@ -77,7 +73,6 @@ const propTypes = {
};
const defaultProps = {
- payPalMeData: {},
bankAccountList: {},
fundList: null,
userWallet: {
@@ -149,14 +144,13 @@ function isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, p
return paymentMethod.accountType === actionPaymentMethodType && paymentMethod.methodID === activePaymentMethodID;
}
function PaymentMethodList(props) {
- const {actionPaymentMethodType, activePaymentMethodID, bankAccountList, fundList, filterType, network, onPress, payPalMeData, shouldShowSelectedState, selectedMethodID, translate} =
- props;
+ const {actionPaymentMethodType, activePaymentMethodID, bankAccountList, fundList, filterType, network, onPress, shouldShowSelectedState, selectedMethodID, translate} = props;
const filteredPaymentMethods = useMemo(() => {
const paymentCardList = fundList || {};
// Hide any billing cards that are not P2P debit cards for now because you cannot make them your default method, or delete them
const filteredCardList = _.filter(paymentCardList, (card) => card.accountData.additionalData.isP2PDebitCard);
- let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList, filteredCardList, payPalMeData);
+ let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList, filteredCardList);
if (!_.isEmpty(filterType)) {
combinedPaymentMethods = _.filter(combinedPaymentMethods, (paymentMethod) => paymentMethod.accountType === filterType);
@@ -180,7 +174,7 @@ function PaymentMethodList(props) {
}));
return combinedPaymentMethods;
- }, [actionPaymentMethodType, activePaymentMethodID, bankAccountList, filterType, network, onPress, payPalMeData, fundList]);
+ }, [actionPaymentMethodType, activePaymentMethodID, bankAccountList, filterType, network, onPress, fundList]);
/**
* Render placeholder when there are no payments methods
@@ -274,9 +268,6 @@ export default compose(
isLoadingPaymentMethods: {
key: ONYXKEYS.IS_LOADING_PAYMENT_METHODS,
},
- payPalMeData: {
- key: ONYXKEYS.PAYPAL,
- },
userWallet: {
key: ONYXKEYS.USER_WALLET,
},
diff --git a/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js b/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js
index 1393892b6ef0..b416ded298e5 100644
--- a/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js
+++ b/src/pages/settings/Wallet/WalletPage/BaseWalletPage.js
@@ -74,7 +74,9 @@ function BaseWalletPage(props) {
* @param {Object} position
*/
const setMenuPosition = useCallback(() => {
- if (!paymentMethodButtonRef.current) return;
+ if (!paymentMethodButtonRef.current) {
+ return;
+ }
const position = getClickedTargetLocation(paymentMethodButtonRef.current);
@@ -89,9 +91,6 @@ function BaseWalletPage(props) {
}, [windowWidth]);
const getSelectedPaymentMethodID = useCallback(() => {
- if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PAYPAL) {
- return CONST.PAYMENT_METHODS.PAYPAL;
- }
if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) {
return paymentMethod.selectedPaymentMethod.bankAccountID;
}
@@ -138,14 +137,7 @@ function BaseWalletPage(props) {
// The delete/default menu
if (accountType) {
let formattedSelectedPaymentMethod;
- if (accountType === CONST.PAYMENT_METHODS.PAYPAL) {
- formattedSelectedPaymentMethod = {
- title: 'PayPal.me',
- icon: account.icon,
- description: PaymentUtils.getPaymentMethodDescription(accountType, account),
- type: CONST.PAYMENT_METHODS.PAYPAL,
- };
- } else if (accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) {
+ if (accountType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) {
formattedSelectedPaymentMethod = {
title: account.addressName,
icon: account.icon,
@@ -190,11 +182,6 @@ function BaseWalletPage(props) {
const addPaymentMethodTypePressed = (paymentType) => {
hideAddPaymentMenu();
- if (paymentType === CONST.PAYMENT_METHODS.PAYPAL) {
- Navigation.navigate(ROUTES.SETTINGS_ADD_PAYPAL_ME);
- return;
- }
-
if (paymentType === CONST.PAYMENT_METHODS.DEBIT_CARD) {
Navigation.navigate(ROUTES.SETTINGS_ADD_DEBIT_CARD);
return;
@@ -241,9 +228,7 @@ function BaseWalletPage(props) {
]);
const deletePaymentMethod = useCallback(() => {
- if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PAYPAL) {
- PaymentMethods.deletePayPalMe();
- } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) {
+ if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.BANK_ACCOUNT) {
BankAccounts.deletePaymentBankAccount(paymentMethod.selectedPaymentMethod.bankAccountID);
} else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD) {
PaymentMethods.deletePaymentCard(paymentMethod.selectedPaymentMethod.fundID);
@@ -254,11 +239,6 @@ function BaseWalletPage(props) {
Navigation.navigate(ROUTES.SETTINGS_WALLET_TRANSFER_BALANCE);
};
- const navigateToAddPaypalRoute = () => {
- Navigation.navigate(ROUTES.SETTINGS_ADD_PAYPAL_ME);
- setShouldShowDefaultDeleteMenu(false);
- };
-
const listHeaderComponent = useCallback(
() => (
<>
@@ -350,8 +330,6 @@ function BaseWalletPage(props) {
shouldResetPaymentMethodData = true;
} else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.DEBIT_CARD && _.isEmpty(props.fundList[paymentMethod.methodID])) {
shouldResetPaymentMethodData = true;
- } else if (paymentMethod.selectedPaymentMethodType === CONST.PAYMENT_METHODS.PAYPAL && _.isEmpty(props.payPalMeData)) {
- shouldResetPaymentMethodData = true;
}
if (shouldResetPaymentMethodData) {
// Close corresponding selected payment method modals which are open
@@ -359,13 +337,11 @@ function BaseWalletPage(props) {
hideDefaultDeleteMenu();
}
}
- }, [hideDefaultDeleteMenu, paymentMethod.methodID, paymentMethod.selectedPaymentMethodType, props.bankAccountList, props.fundList, props.payPalMeData, shouldShowDefaultDeleteMenu]);
+ }, [hideDefaultDeleteMenu, paymentMethod.methodID, paymentMethod.selectedPaymentMethodType, props.bankAccountList, props.fundList, shouldShowDefaultDeleteMenu]);
- const isPayPalMeSelected = paymentMethod.formattedSelectedPaymentMethod.type === CONST.PAYMENT_METHODS.PAYPAL;
const shouldShowMakeDefaultButton =
!paymentMethod.isSelectedPaymentMethodDefault &&
Permissions.canUseWallet(props.betas) &&
- !isPayPalMeSelected &&
!(paymentMethod.formattedSelectedPaymentMethod.type === CONST.PAYMENT_METHODS.BANK_ACCOUNT && paymentMethod.selectedPaymentMethod.type === CONST.BANK_ACCOUNT.TYPE.BUSINESS);
// Determines whether or not the modal popup is mounted from the bottom of the screen instead of the side mount on Web or Desktop screens
@@ -438,14 +414,6 @@ function BaseWalletPage(props) {
text={translate('walletPage.setDefaultConfirmation')}
/>
)}
- {isPayPalMeSelected && (
-
- )}
diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.js b/src/pages/tasks/TaskShareDestinationSelectorModal.js
index 15e3f03964e6..44d7b1f6a633 100644
--- a/src/pages/tasks/TaskShareDestinationSelectorModal.js
+++ b/src/pages/tasks/TaskShareDestinationSelectorModal.js
@@ -1,5 +1,5 @@
/* eslint-disable es/no-optional-chaining */
-import React, {useState, useEffect, useMemo, useCallback} from 'react';
+import React, {useState, useEffect, useMemo, useCallback, useRef} from 'react';
import _ from 'underscore';
import {View} from 'react-native';
import PropTypes from 'prop-types';
@@ -46,10 +46,16 @@ function TaskShareDestinationSelectorModal(props) {
const [headerMessage, setHeaderMessage] = useState('');
const [filteredRecentReports, setFilteredRecentReports] = useState([]);
+ const optionRef = useRef();
+
const filteredReports = useMemo(() => {
const reports = {};
_.keys(props.reports).forEach((reportKey) => {
- if (ReportUtils.shouldDisableWriteActions(props.reports[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(props.reports[reportKey])) {
+ if (
+ ReportUtils.shouldDisableWriteActions(props.reports[reportKey]) ||
+ ReportUtils.isExpensifyOnlyParticipantInReport(props.reports[reportKey]) ||
+ ReportUtils.isCanceledTaskReport(props.reports[reportKey])
+ ) {
return;
}
reports[reportKey] = props.reports[reportKey];
@@ -107,7 +113,10 @@ function TaskShareDestinationSelectorModal(props) {
const sections = getSections();
return (
-
+ optionRef.current && optionRef.current.textInput.focus()}
+ >
{({didScreenTransitionEnd, safeAreaPaddingBottomStyle}) => (
<>
>
diff --git a/src/pages/tasks/TaskTitlePage.js b/src/pages/tasks/TaskTitlePage.js
index 9a7a36a1e119..be0884e971ae 100644
--- a/src/pages/tasks/TaskTitlePage.js
+++ b/src/pages/tasks/TaskTitlePage.js
@@ -100,7 +100,9 @@ function TaskTitlePage(props) {
accessibilityLabel={props.translate('task.title')}
defaultValue={(props.report && props.report.reportName) || ''}
ref={(el) => {
- if (!el) return;
+ if (!el) {
+ return;
+ }
if (!inputRef.current && didScreenTransitionEnd) {
el.focus();
}
diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.js b/src/pages/workspace/WorkspaceInviteMessagePage.js
index 9a046d7fe4c2..3baf84f54ccf 100644
--- a/src/pages/workspace/WorkspaceInviteMessagePage.js
+++ b/src/pages/workspace/WorkspaceInviteMessagePage.js
@@ -122,7 +122,7 @@ class WorkspaceInviteMessagePage extends React.Component {
Policy.addMembersToWorkspace(this.props.invitedEmailsToAccountIDsDraft, this.state.welcomeNote, this.props.route.params.policyID);
Policy.setWorkspaceInviteMembersDraft(this.props.route.params.policyID, {});
// Pop the invite message page before navigating to the members page.
- Navigation.goBack();
+ Navigation.goBack(ROUTES.HOME);
Navigation.navigate(ROUTES.getWorkspaceMembersRoute(this.props.route.params.policyID));
}
@@ -171,7 +171,6 @@ class WorkspaceInviteMessagePage extends React.Component {
guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_MEMBERS}
shouldShowBackButton
onCloseButtonPress={() => Navigation.dismissModal()}
- onBackButtonPress={() => Navigation.goBack()}
/>