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 d9eb60471773..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 1001037005
- versionName "1.3.70-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..0a88ecd7bda8 100644
--- a/contributingGuides/STYLE.md
+++ b/contributingGuides/STYLE.md
@@ -491,6 +491,19 @@ When writing a function component you must ALWAYS add a `displayName` property a
export default Avatar;
```
+## Forwarding refs
+
+When forwarding a ref define named component and pass it directly to the `forwardRef`. By doing this we remove potential extra layer in React tree in form of anonymous component.
+
+```javascript
+ function FancyInput(props, ref) {
+ ...
+ return
+ }
+
+ export default React.forwardRef(FancyInput)
+```
+
## Stateless components vs Pure Components vs Class based components vs Render Props - When to use what?
Class components are DEPRECATED. Use function components and React hooks.
@@ -567,6 +580,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/contributingGuides/TS_CHEATSHEET.md b/contributingGuides/TS_CHEATSHEET.md
index df6d70b5ae90..1e330dafb7cf 100644
--- a/contributingGuides/TS_CHEATSHEET.md
+++ b/contributingGuides/TS_CHEATSHEET.md
@@ -43,7 +43,9 @@
- [1.2](#forwardRef) **`forwardRef`**
```ts
- import { forwardRef, useRef, ReactNode } from "react";
+ // CustomTextInput.tsx
+
+ import { forwardRef, useRef, ReactNode, ForwardedRef } from "react";
import { TextInput, View } from "react-native";
export type CustomTextInputProps = {
@@ -51,16 +53,18 @@
children?: ReactNode;
};
- const CustomTextInput = forwardRef(
- (props, ref) => {
- return (
-
-
- {props.children}
-
- );
- }
- );
+ function CustomTextInput(props: CustomTextInputProps, ref: ForwardedRef) {
+ return (
+
+
+ {props.children}
+
+ );
+ };
+
+ export default forwardRef(CustomTextInput);
+
+ // ParentComponent.tsx
function ParentComponent() {
const ref = useRef();
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/docs/assets/js/main.js b/docs/assets/js/main.js
index 01ebb00b288c..f0f335536c20 100644
--- a/docs/assets/js/main.js
+++ b/docs/assets/js/main.js
@@ -206,13 +206,6 @@ window.addEventListener('DOMContentLoaded', () => {
// If there is a fixed article scroll container, set to calculate titles' offset
scrollContainer: 'content-area',
-
- // onclick function to apply to all links in toc. will be called with
- // the event as the first parameter, and this can be used to stop,
- // propagation, prevent default or perform action
- onClick() {
- toggleHeaderMenu();
- },
});
}
@@ -226,6 +219,18 @@ window.addEventListener('DOMContentLoaded', () => {
const articleContent = document.getElementById('article-content');
const lhnContent = document.getElementById('lhn-content');
+
+ // This event listener checks if a link clicked in the LHN points to some section of the same page and toggles
+ // the LHN menu in responsive view.
+ lhnContent.addEventListener('click', (event) => {
+ const clickedLink = event.target;
+ if (clickedLink) {
+ const href = clickedLink.getAttribute('href');
+ if (href && href.startsWith('#') && !!document.getElementById(href.slice(1))) {
+ toggleHeaderMenu();
+ }
+ }
+ });
lhnContent.addEventListener('wheel', (e) => {
const scrollTop = lhnContent.scrollTop;
const isScrollingPastLHNTop = e.deltaY < 0 && scrollTop === 0;
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 440e48e0c83d..441bd2feab92 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.3.70
+ 1.3.72
CFBundleSignature
????
CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.3.70.5
+ 1.3.72.9
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 9d7fc804acd9..27273c7f3866 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.3.70
+ 1.3.72
CFBundleSignature
????
CFBundleVersion
- 1.3.70.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 3e08356a76ef..ff0500eb385b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.70-5",
+ "version": "1.3.72-9",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.70-5",
+ "version": "1.3.72-9",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -52,7 +52,6 @@
"domhandler": "^4.3.0",
"expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#35bff866a8d345b460ea6256f0a0f0a8a7f81086",
"fbjs": "^3.0.2",
- "focus-trap-react": "^10.2.1",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
"jest-when": "^3.5.2",
@@ -70,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",
@@ -81,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",
@@ -90,10 +90,10 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "1.0.76",
+ "react-native-onyx": "1.0.84",
"react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.7.1",
- "react-native-performance": "^4.0.0",
+ "react-native-performance": "^5.1.0",
"react-native-permissions": "^3.0.1",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2",
"react-native-plaid-link-sdk": "^10.0.0",
@@ -103,7 +103,7 @@
"react-native-render-html": "6.3.1",
"react-native-safe-area-context": "4.4.1",
"react-native-screens": "3.21.0",
- "react-native-svg": "^13.9.0",
+ "react-native-svg": "^13.13.0",
"react-native-tab-view": "^3.5.2",
"react-native-url-polyfill": "^2.0.0",
"react-native-view-shot": "^3.6.0",
@@ -139,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",
@@ -204,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",
@@ -6726,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",
@@ -6746,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"
@@ -6756,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"
@@ -6831,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",
@@ -6954,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",
@@ -6979,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",
@@ -7044,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",
@@ -7075,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"
@@ -7156,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",
@@ -7232,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",
@@ -7309,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",
@@ -7326,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",
@@ -7355,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",
@@ -7371,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",
@@ -7379,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",
@@ -7390,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",
@@ -7484,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",
@@ -7495,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"
}
},
@@ -7571,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",
@@ -7591,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"
}
@@ -7736,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",
@@ -7990,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": {
@@ -8011,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"
@@ -21038,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",
@@ -21104,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",
@@ -22669,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"
},
@@ -23138,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",
@@ -23159,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",
@@ -23182,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"
},
@@ -23196,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"
}
@@ -24572,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",
@@ -28295,28 +28882,6 @@
"readable-stream": "^2.3.6"
}
},
- "node_modules/focus-trap": {
- "version": "7.5.2",
- "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.2.tgz",
- "integrity": "sha512-p6vGNNWLDGwJCiEjkSK6oERj/hEyI9ITsSwIUICBoKLlWiTWXJRfQibCwcoi50rTZdbi87qDtUlMCmQwsGSgPw==",
- "dependencies": {
- "tabbable": "^6.2.0"
- }
- },
- "node_modules/focus-trap-react": {
- "version": "10.2.1",
- "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-10.2.1.tgz",
- "integrity": "sha512-UrAKOn52lvfHF6lkUMfFhlQxFgahyNW5i6FpHWkDxAeD4FSk3iwx9n4UEA4Sims0G5WiGIi0fAyoq3/UVeNCYA==",
- "dependencies": {
- "focus-trap": "^7.5.2",
- "tabbable": "^6.2.0"
- },
- "peerDependencies": {
- "prop-types": "^15.8.1",
- "react": ">=16.3.0",
- "react-dom": ">=16.3.0"
- }
- },
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
@@ -33594,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",
@@ -34256,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",
@@ -35643,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",
@@ -35669,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",
@@ -35704,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",
@@ -35717,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": {
@@ -35729,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"
@@ -35757,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",
@@ -35771,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"
@@ -35783,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"
@@ -35795,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",
@@ -35840,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",
@@ -35855,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": "*"
}
@@ -35863,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"
},
@@ -35877,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"
@@ -35892,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"
},
@@ -35902,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"
}
@@ -35916,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"
}
@@ -35924,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"
}
@@ -35932,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": "*",
@@ -35948,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",
@@ -35961,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"
},
@@ -35974,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"
},
@@ -35988,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",
@@ -36009,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",
@@ -36022,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"
}
@@ -36029,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"
},
@@ -36055,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"
}
@@ -36063,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",
@@ -36080,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"
},
@@ -36096,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"
},
@@ -36107,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",
@@ -36160,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": {
@@ -36184,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"
@@ -36212,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"
},
@@ -36238,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",
@@ -36265,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",
@@ -36280,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": {
@@ -36305,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"
},
@@ -36319,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"
@@ -36333,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",
@@ -36352,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"
},
@@ -36362,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"
}
@@ -36376,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"
}
@@ -36384,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",
@@ -36397,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"
},
@@ -36410,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"
}
@@ -36424,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"
}
@@ -36432,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"
},
@@ -36443,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"
},
@@ -36463,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"
}
@@ -36471,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",
@@ -36488,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"
}
@@ -38030,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"
}
@@ -40210,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",
@@ -40257,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",
@@ -40281,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",
@@ -40462,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",
@@ -40567,9 +41203,9 @@
}
},
"node_modules/react-native-onyx": {
- "version": "1.0.76",
- "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.76.tgz",
- "integrity": "sha512-mcMlYQCo1B/kom+4hu7CQKKLwvPFjQAJsVIzV2s9aa8XKNlcnYiJbfuM6RSJ1fFmSIeud4Y66rhv4/oWUkSl5A==",
+ "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",
@@ -40582,8 +41218,9 @@
"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": "^4.0.0",
+ "react-native-performance": "^5.1.0",
"react-native-quick-sqlite": "^8.0.0-beta.2"
},
"peerDependenciesMeta": {
@@ -40625,8 +41262,9 @@
}
},
"node_modules/react-native-performance": {
- "version": "4.0.0",
- "license": "MIT",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-5.1.0.tgz",
+ "integrity": "sha512-rq/YBf0/GptSOM/Lj64/1yRq8uN2YE0psFB16wFbYBbTcIEp/0rrgN2HyS5lhvfBOFgKoDRWQ53jHSCb+QJ5eA==",
"peerDependencies": {
"react-native": "*"
}
@@ -40783,8 +41421,9 @@
}
},
"node_modules/react-native-svg": {
- "version": "13.9.0",
- "license": "MIT",
+ "version": "13.13.0",
+ "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.13.0.tgz",
+ "integrity": "sha512-L8y8uEiMG0Tr++Nb2+24wlMuv18+bmq/CMoFFtTUlEqVvGCoK2ea8WamPl/9bV8gjL+Rngg5NqEBvKS23sbYoA==",
"dependencies": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3"
@@ -44692,11 +45331,6 @@
"dev": true,
"license": "BSD-3-Clause"
},
- "node_modules/tabbable": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
- "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
- },
"node_modules/table": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
@@ -45023,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",
@@ -46394,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",
@@ -52518,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",
@@ -52538,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": {
@@ -52637,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",
@@ -52658,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"
@@ -52714,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",
@@ -52806,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",
@@ -52831,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",
@@ -52878,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",
@@ -52902,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"
@@ -52964,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",
@@ -53021,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",
@@ -53079,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",
@@ -53096,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",
@@ -53113,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",
@@ -53126,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",
@@ -53138,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",
@@ -53208,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",
@@ -53219,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": {
@@ -53271,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",
@@ -53287,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"
}
@@ -53433,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": {
@@ -53453,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"
@@ -62665,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",
@@ -62722,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",
@@ -63801,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",
@@ -64122,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",
@@ -64131,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",
@@ -64148,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=="
}
}
},
@@ -65089,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"
@@ -67708,23 +68805,6 @@
"readable-stream": "^2.3.6"
}
},
- "focus-trap": {
- "version": "7.5.2",
- "resolved": "https://registry.npmjs.org/focus-trap/-/focus-trap-7.5.2.tgz",
- "integrity": "sha512-p6vGNNWLDGwJCiEjkSK6oERj/hEyI9ITsSwIUICBoKLlWiTWXJRfQibCwcoi50rTZdbi87qDtUlMCmQwsGSgPw==",
- "requires": {
- "tabbable": "^6.2.0"
- }
- },
- "focus-trap-react": {
- "version": "10.2.1",
- "resolved": "https://registry.npmjs.org/focus-trap-react/-/focus-trap-react-10.2.1.tgz",
- "integrity": "sha512-UrAKOn52lvfHF6lkUMfFhlQxFgahyNW5i6FpHWkDxAeD4FSk3iwx9n4UEA4Sims0G5WiGIi0fAyoq3/UVeNCYA==",
- "requires": {
- "focus-trap": "^7.5.2",
- "tabbable": "^6.2.0"
- }
- },
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
@@ -71206,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",
@@ -71666,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",
@@ -72670,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",
@@ -72696,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",
@@ -72728,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"
}
@@ -72736,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"
@@ -72744,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",
@@ -72760,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"
}
@@ -72767,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"
}
@@ -72780,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",
@@ -72796,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"
}
@@ -72805,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"
}
@@ -72829,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",
@@ -72853,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",
@@ -72868,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",
@@ -72910,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"
@@ -72919,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"
@@ -72927,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",
@@ -72964,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",
@@ -72976,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": "*"
}
@@ -72984,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"
}
@@ -72992,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"
@@ -73001,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"
}
@@ -73008,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"
}
@@ -73021,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": "*",
@@ -73045,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",
@@ -73055,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"
}
@@ -73064,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"
}
@@ -73077,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",
@@ -73092,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",
@@ -73102,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"
}
@@ -73109,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",
@@ -73139,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",
@@ -73206,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"
@@ -73244,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"
},
@@ -73266,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",
@@ -73286,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",
@@ -73298,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"
}
},
@@ -74354,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"
@@ -75785,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": {}
@@ -75809,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",
@@ -75833,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",
@@ -76060,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",
@@ -76116,9 +77265,9 @@
}
},
"react-native-onyx": {
- "version": "1.0.76",
- "resolved": "https://registry.npmjs.org/react-native-onyx/-/react-native-onyx-1.0.76.tgz",
- "integrity": "sha512-mcMlYQCo1B/kom+4hu7CQKKLwvPFjQAJsVIzV2s9aa8XKNlcnYiJbfuM6RSJ1fFmSIeud4Y66rhv4/oWUkSl5A==",
+ "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",
@@ -76141,7 +77290,9 @@
}
},
"react-native-performance": {
- "version": "4.0.0",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/react-native-performance/-/react-native-performance-5.1.0.tgz",
+ "integrity": "sha512-rq/YBf0/GptSOM/Lj64/1yRq8uN2YE0psFB16wFbYBbTcIEp/0rrgN2HyS5lhvfBOFgKoDRWQ53jHSCb+QJ5eA==",
"requires": {}
},
"react-native-performance-flipper-reporter": {
@@ -76238,7 +77389,9 @@
}
},
"react-native-svg": {
- "version": "13.9.0",
+ "version": "13.13.0",
+ "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-13.13.0.tgz",
+ "integrity": "sha512-L8y8uEiMG0Tr++Nb2+24wlMuv18+bmq/CMoFFtTUlEqVvGCoK2ea8WamPl/9bV8gjL+Rngg5NqEBvKS23sbYoA==",
"requires": {
"css-select": "^5.1.0",
"css-tree": "^1.1.3"
@@ -78848,11 +80001,6 @@
"version": "2.0.15",
"dev": true
},
- "tabbable": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
- "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
- },
"table": {
"version": "6.8.1",
"resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz",
@@ -79079,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",
@@ -79983,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 221c3fa7cbf2..44b936c8c588 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.70-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.",
@@ -94,7 +94,6 @@
"domhandler": "^4.3.0",
"expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#35bff866a8d345b460ea6256f0a0f0a8a7f81086",
"fbjs": "^3.0.2",
- "focus-trap-react": "^10.2.1",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
"jest-when": "^3.5.2",
@@ -113,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",
@@ -123,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",
@@ -132,10 +132,10 @@
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
- "react-native-onyx": "1.0.76",
+ "react-native-onyx": "1.0.84",
"react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.7.1",
- "react-native-performance": "^4.0.0",
+ "react-native-performance": "^5.1.0",
"react-native-permissions": "^3.0.1",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2",
"react-native-plaid-link-sdk": "^10.0.0",
@@ -145,7 +145,7 @@
"react-native-render-html": "6.3.1",
"react-native-safe-area-context": "4.4.1",
"react-native-screens": "3.21.0",
- "react-native-svg": "^13.9.0",
+ "react-native-svg": "^13.13.0",
"react-native-tab-view": "^3.5.2",
"react-native-url-polyfill": "^2.0.0",
"react-native-view-shot": "^3.6.0",
@@ -181,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",
@@ -246,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 8c437a9f47cc..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',
@@ -1170,6 +1178,7 @@ const CONST = {
SMALL_NORMAL: 'small-normal',
},
EXPENSIFY_CARD: {
+ BANK: 'Expensify Card',
FRAUD_TYPES: {
DOMAIN: 'domain',
INDIVIDUAL: 'individal',
@@ -1200,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
@@ -1304,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,
@@ -1342,6 +1350,7 @@ const CONST = {
SETTINGS: 'settings',
LEAVE_ROOM: 'leaveRoom',
WELCOME_MESSAGE: 'welcomeMessage',
+ PRIVATE_NOTES: 'privateNotes',
},
EDIT_REQUEST_FIELD: {
AMOUNT: 'amount',
@@ -1349,6 +1358,7 @@ const CONST = {
DATE: 'date',
DESCRIPTION: 'description',
MERCHANT: 'merchant',
+ RECEIPT: 'receipt',
},
FOOTER: {
EXPENSE_MANAGEMENT_URL: `${USE_EXPENSIFY_URL}/expense-management`,
@@ -2530,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',
@@ -2655,6 +2639,7 @@ const CONST = {
INDENTS: ' ',
PARENT_CHILD_SEPARATOR: ': ',
CATEGORY_LIST_THRESHOLD: 8,
+ TAG_LIST_THRESHOLD: 8,
DEMO_PAGES: {
SAASTR: 'SaaStrDemoSetup',
SBE: 'SbeDemoSetup',
@@ -2670,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 1086bd32cff9..9e6ae1ff27b4 100644
--- a/src/Expensify.js
+++ b/src/Expensify.js
@@ -30,7 +30,6 @@ import KeyboardShortcutsModal from './components/KeyboardShortcutsModal';
import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
import EmojiPicker from './components/EmojiPicker/EmojiPicker';
import * as EmojiPickerAction from './libs/actions/EmojiPickerAction';
-import DownloadAppModal from './components/DownloadAppModal';
import DeeplinkWrapper from './components/DeeplinkWrapper';
// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
@@ -100,7 +99,9 @@ function Expensify(props) {
const [hasAttemptedToOpenPublicRoom, setAttemptedToOpenPublicRoom] = useState(false);
useEffect(() => {
- if (props.isCheckingPublicRoom) return;
+ if (props.isCheckingPublicRoom) {
+ return;
+ }
setAttemptedToOpenPublicRoom(true);
}, [props.isCheckingPublicRoom]);
@@ -193,7 +194,6 @@ function Expensify(props) {
{shouldInit && (
<>
-
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 2e0b75910bae..05256f2b806c 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';
@@ -87,13 +88,7 @@ const ONYXKEYS = {
SESSION: 'session',
BETAS: 'betas',
- /** Denotes if the Download App Banner has been dismissed */
- SHOW_DOWNLOAD_APP_BANNER: 'showDownloadAppBanner',
-
/** NVP keys
- * Contains the user's payPalMe data */
- PAYPAL: 'paypal',
-
/** Contains the user preference for the LHN priority mode */
NVP_PRIORITY_MODE: 'nvp_priorityMode',
@@ -175,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',
@@ -284,12 +282,12 @@ 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',
SETTINGS_STATUS_CLEAR_AFTER_FORM: 'settingsStatusClearAfterForm',
SETTINGS_STATUS_SET_CLEAR_AFTER_FORM: 'settingsStatusSetClearAfterForm',
+ PRIVATE_NOTES_FORM: 'privateNotesForm',
I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm',
INTRO_SCHOOL_PRINCIPAL_FORM: 'introSchoolPrincipalForm',
},
@@ -306,9 +304,8 @@ type OnyxValues = {
[ONYXKEYS.ACTIVE_CLIENTS]: string[];
[ONYXKEYS.DEVICE_ID]: string;
[ONYXKEYS.IS_SIDEBAR_LOADED]: boolean;
- [ONYXKEYS.SHOW_DOWNLOAD_APP_BANNER]: 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;
@@ -327,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;
@@ -366,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;
@@ -419,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 36260058e741..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',
@@ -173,6 +172,14 @@ export default {
GOOGLE_SIGN_IN: 'sign-in-with-google',
DESKTOP_SIGN_IN_REDIRECT: 'desktop-signin-redirect',
+ // Routes related to private notes added to the report
+ PRIVATE_NOTES_VIEW: 'r/:reportID/notes/:accountID',
+ getPrivateNotesViewRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}`,
+ PRIVATE_NOTES_LIST: 'r/:reportID/notes',
+ getPrivateNotesListRoute: (reportID: string) => `r/${reportID}/notes`,
+ PRIVATE_NOTES_EDIT: 'r/:reportID/notes/:accountID/edit',
+ getPrivateNotesEditRoute: (reportID: string, accountID: string | number) => `r/${reportID}/notes/${accountID}/edit`,
+
// This is a special validation URL that will take the user to /workspace/new after validation. This is used
// when linking users from e.com in order to share a session in this app.
ENABLE_PAYMENTS: '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/AnimatedStep/index.js b/src/components/AnimatedStep/index.js
index a8b9b80fcc0e..5b0dc8bc78fa 100644
--- a/src/components/AnimatedStep/index.js
+++ b/src/components/AnimatedStep/index.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import * as Animatable from 'react-native-animatable';
import CONST from '../../CONST';
import styles from '../../styles/styles';
+import useNativeDriver from '../../libs/useNativeDriver';
const propTypes = {
/** Children to wrap in AnimatedStep. */
@@ -47,7 +48,7 @@ function AnimatedStep(props) {
}}
duration={CONST.ANIMATED_TRANSITION}
animation={getAnimationStyle(props.direction)}
- useNativeDriver
+ useNativeDriver={useNativeDriver}
style={props.style}
>
{props.children}
diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js
index d39906faf3a3..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,11 @@ 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';
/**
* Modal render prop component that exposes modal launching triggers that can be used
@@ -93,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);
@@ -105,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
? {
@@ -294,7 +302,7 @@ function AttachmentModal(props) {
Animated.timing(confirmButtonFadeAnimation, {
toValue,
duration: 100,
- useNativeDriver: true,
+ useNativeDriver,
}).start();
},
[confirmButtonFadeAnimation],
@@ -330,6 +338,10 @@ function AttachmentModal(props) {
}}
onModalHide={(e) => {
props.onModalHide(e);
+ if (onModalHideCallbackRef.current) {
+ onModalHideCallbackRef.current();
+ }
+
setShouldLoadAttachment(false);
}}
propagateSwipe
@@ -338,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/extractAttachmentsFromReport.js b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js
index d5da25c89576..8a623a44709f 100644
--- a/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js
+++ b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js
@@ -59,6 +59,7 @@ function extractAttachmentsFromReport(report, reportActions) {
isAuthTokenRequired: true,
file: {name: transaction.filename},
isReceipt: true,
+ transactionID,
});
return;
}
diff --git a/src/components/Attachments/AttachmentCarousel/index.js b/src/components/Attachments/AttachmentCarousel/index.js
index 5c731a0ccfee..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,13 +13,13 @@ 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';
import * as Illustrations from '../../Icon/Illustrations';
import variables from '../../../styles/variables';
import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
+import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
const viewabilityConfig = {
// To facilitate paging through the attachments, we want to consider an item "viewable" when it is
@@ -29,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);
@@ -38,13 +38,25 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, setDownl
const [activeSource, setActiveSource] = useState(source);
const [shouldShowArrows, setShouldShowArrows, autoHideArrows, cancelAutoHideArrows] = useCarouselArrows();
+ const compareImage = useCallback(
+ (attachment) => {
+ if (attachment.isReceipt) {
+ const action = ReportActionsUtils.getParentReportAction(report);
+ const transactionID = _.get(action, ['originalMessage', 'IOUTransactionID']);
+ return attachment.transactionID === transactionID;
+ }
+ return attachment.source === source;
+ },
+ [source, report],
+ );
+
useEffect(() => {
const attachmentsFromReport = extractAttachmentsFromReport(report, reportActions);
- const initialPage = _.findIndex(attachmentsFromReport, (a) => a.source === source);
+ const initialPage = _.findIndex(attachmentsFromReport, compareImage);
// Dismiss the modal when deleting an attachment during its display in preview.
- if (initialPage === -1 && _.find(attachments, (a) => a.source === source)) {
+ if (initialPage === -1 && _.find(attachments, compareImage)) {
Navigation.dismissModal();
} else {
setPage(initialPage);
@@ -54,10 +66,12 @@ 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
- }, [report, reportActions, source]);
+ }, [reportActions, compareImage]);
/**
* Updates the page state when the user navigates between attachments
@@ -117,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
@@ -211,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 95cda7c2f5c9..bd12020341be 100644
--- a/src/components/Attachments/AttachmentCarousel/index.native.js
+++ b/src/components/Attachments/AttachmentCarousel/index.native.js
@@ -16,6 +16,7 @@ import * as Illustrations from '../../Icon/Illustrations';
import variables from '../../../styles/variables';
import compose from '../../../libs/compose';
import withLocalize from '../../withLocalize';
+import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
function AttachmentCarousel({report, reportActions, source, onNavigate, onClose, setDownloadButtonVisibility, translate}) {
const pagerRef = useRef(null);
@@ -27,13 +28,25 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, onClose,
const [isPinchGestureRunning, setIsPinchGestureRunning] = useState(true);
const [shouldShowArrows, setShouldShowArrows, autoHideArrows, cancelAutoHideArrows] = useCarouselArrows();
+ const compareImage = useCallback(
+ (attachment) => {
+ if (attachment.isReceipt) {
+ const action = ReportActionsUtils.getParentReportAction(report);
+ const transactionID = _.get(action, ['originalMessage', 'IOUTransactionID']);
+ return attachment.transactionID === transactionID;
+ }
+ return attachment.source === source;
+ },
+ [source, report],
+ );
+
useEffect(() => {
const attachmentsFromReport = extractAttachmentsFromReport(report, reportActions);
- const initialPage = _.findIndex(attachmentsFromReport, (a) => a.source === source);
+ const initialPage = _.findIndex(attachmentsFromReport, compareImage);
// Dismiss the modal when deleting an attachment during its display in preview.
- if (initialPage === -1 && _.find(attachments, (a) => a.source === source)) {
+ if (initialPage === -1 && _.find(attachments, compareImage)) {
Navigation.dismissModal();
} else {
setPage(initialPage);
@@ -43,10 +56,12 @@ 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
- }, [report, reportActions, source]);
+ }, [reportActions, compareImage]);
/**
* Updates the page state when the user navigates between attachments
@@ -135,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/Button/index.js b/src/components/Button/index.js
index bfde528a4750..c16860344837 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -218,6 +218,7 @@ class Button extends Component {
this.props.icon && styles.textAlignLeft,
...this.props.textStyles,
]}
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
{this.props.text}
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 4ee429a2e389..b24b5b5ba879 100644
--- a/src/components/CategoryPicker/index.js
+++ b/src/components/CategoryPicker/index.js
@@ -35,7 +35,20 @@ function CategoryPicker({policyCategories, reportID, iouType, iou, policyRecentl
}, [iou.category]);
const sections = useMemo(() => {
- const {categoryOptions} = OptionsListUtils.getNewChatOptions({}, {}, [], searchValue, selectedOptions, [], false, false, true, policyCategories, policyRecentlyUsedCategories, false);
+ const {categoryOptions} = OptionsListUtils.getFilteredOptions(
+ {},
+ {},
+ [],
+ searchValue,
+ selectedOptions,
+ [],
+ false,
+ false,
+ true,
+ policyCategories,
+ policyRecentlyUsedCategories,
+ false,
+ );
return categoryOptions;
}, [policyCategories, policyRecentlyUsedCategories, searchValue, selectedOptions]);
diff --git a/src/components/CollapsibleSection/index.js b/src/components/CollapsibleSection/index.js
index e9c3a90a7b30..7009d1905e1d 100644
--- a/src/components/CollapsibleSection/index.js
+++ b/src/components/CollapsibleSection/index.js
@@ -51,6 +51,7 @@ class CollapsibleSection extends React.Component {
{this.props.title}
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/ConfirmContent.js b/src/components/ConfirmContent.js
index 9a72d4e7d584..ab3e23d6b1c1 100644
--- a/src/components/ConfirmContent.js
+++ b/src/components/ConfirmContent.js
@@ -100,8 +100,8 @@ function ConfirmContent(props) {
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 previousValidatedWaypoints = usePrevious(validatedWaypoints);
+ const haveValidatedWaypointsChanged = !_.isEqual(previousValidatedWaypoints, validatedWaypoints);
+ 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;
}
@@ -188,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 = () => {
@@ -260,7 +261,10 @@ function DistanceRequest({iou, iouType, report, transaction, mapboxAccessToken,
diff --git a/src/components/DownloadAppModal.js b/src/components/DownloadAppModal.js
deleted file mode 100644
index c96c6b3d28c0..000000000000
--- a/src/components/DownloadAppModal.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import React, {useState} from 'react';
-import PropTypes from 'prop-types';
-import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
-import styles from '../styles/styles';
-import CONST from '../CONST';
-import AppIcon from '../../assets/images/expensify-app-icon.svg';
-import useLocalize from '../hooks/useLocalize';
-import * as Link from '../libs/actions/Link';
-import * as Browser from '../libs/Browser';
-import getOperatingSystem from '../libs/getOperatingSystem';
-import setShowDownloadAppModal from '../libs/actions/DownloadAppModal';
-import ConfirmModal from './ConfirmModal';
-
-const propTypes = {
- /** ONYX PROP to hide banner for a user that has dismissed it */
- // eslint-disable-next-line react/forbid-prop-types
- showDownloadAppBanner: PropTypes.bool,
-
- /** Whether the user is logged in */
- isAuthenticated: PropTypes.bool.isRequired,
-};
-
-const defaultProps = {
- showDownloadAppBanner: true,
-};
-
-function DownloadAppModal({isAuthenticated, showDownloadAppBanner}) {
- const [shouldShowBanner, setShouldShowBanner] = useState(Browser.isMobile() && isAuthenticated && showDownloadAppBanner);
-
- const {translate} = useLocalize();
-
- const handleCloseBanner = () => {
- setShowDownloadAppModal(false);
- setShouldShowBanner(false);
- };
-
- let link = '';
-
- if (getOperatingSystem() === CONST.OS.IOS) {
- link = CONST.APP_DOWNLOAD_LINKS.IOS;
- } else if (getOperatingSystem() === CONST.OS.ANDROID) {
- link = CONST.APP_DOWNLOAD_LINKS.ANDROID;
- }
-
- const handleOpenAppStore = () => {
- setShowDownloadAppModal(false);
- setShouldShowBanner(false);
- Link.openExternalLink(link, true);
- };
-
- return (
-
- );
-}
-
-DownloadAppModal.displayName = 'DownloadAppModal';
-DownloadAppModal.propTypes = propTypes;
-DownloadAppModal.defaultProps = defaultProps;
-
-export default withOnyx({
- showDownloadAppBanner: {
- key: ONYXKEYS.SHOW_DOWNLOAD_APP_BANNER,
- },
-})(DownloadAppModal);
diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js
index 40d91ff03267..a12b089ddf97 100644
--- a/src/components/EmojiPicker/EmojiPicker.js
+++ b/src/components/EmojiPicker/EmojiPicker.js
@@ -114,9 +114,11 @@ const EmojiPicker = forwardRef((props, ref) => {
*/
const isActive = (id) => Boolean(id) && id === activeID;
+ const clearActive = () => setActiveID(null);
+
const resetEmojiPopoverAnchor = () => (emojiPopoverAnchor.current = null);
- useImperativeHandle(ref, () => ({showEmojiPicker, isActive, hideEmojiPicker, isEmojiPickerVisible, resetEmojiPopoverAnchor}));
+ useImperativeHandle(ref, () => ({showEmojiPicker, isActive, clearActive, hideEmojiPicker, isEmojiPickerVisible, resetEmojiPopoverAnchor}));
useEffect(() => {
const emojiPopoverDimensionListener = Dimensions.addEventListener('change', () => {
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/EmojiPicker/EmojiPickerMenuItem/index.js b/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
index 728e56792ddb..b51a8b07537c 100644
--- a/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
@@ -72,15 +72,16 @@ class EmojiPickerMenuItem extends PureComponent {
this.props.onPress(this.props.emoji)}
+ onPressOut={Browser.isMobile() ? this.props.onHoverOut : undefined}
onHoverIn={this.props.onHoverIn}
onHoverOut={this.props.onHoverOut}
onFocus={this.props.onFocus}
onBlur={this.props.onBlur}
ref={(ref) => (this.ref = ref)}
style={({pressed}) => [
- Browser.isMobile() && StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)),
this.props.isHighlighted && this.props.isUsingKeyboardMovement ? styles.emojiItemKeyboardHighlighted : {},
this.props.isHighlighted && !this.props.isUsingKeyboardMovement ? styles.emojiItemHighlighted : {},
+ Browser.isMobile() && StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)),
styles.emojiItem,
]}
accessibilityLabel={this.props.emoji}
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/FocusTrapView/index.js b/src/components/FocusTrapView/index.js
deleted file mode 100644
index 2dcab7b9d998..000000000000
--- a/src/components/FocusTrapView/index.js
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * The FocusTrap is only used on web and desktop
- */
-import React, {useEffect, useRef} from 'react';
-import FocusTrap from 'focus-trap-react';
-import {View} from 'react-native';
-import {PropTypes} from 'prop-types';
-import {useIsFocused} from '@react-navigation/native';
-
-const propTypes = {
- /** Children to wrap with FocusTrap */
- children: PropTypes.node.isRequired,
-
- /** Whether to enable the FocusTrap */
- enabled: PropTypes.bool,
-
- /**
- * Whether to disable auto focus
- * It is used when the component inside the FocusTrap have their own auto focus logic
- */
- shouldEnableAutoFocus: PropTypes.bool,
-};
-
-const defaultProps = {
- enabled: true,
- shouldEnableAutoFocus: false,
-};
-
-function FocusTrapView({enabled, shouldEnableAutoFocus, ...props}) {
- const isFocused = useIsFocused();
-
- /**
- * Focus trap always needs a focusable element.
- * In case that we don't have any focusable elements in the modal,
- * the FocusTrap will use fallback View element using this ref.
- */
- const ref = useRef(null);
-
- /**
- * We have to set the 'tabindex' attribute to 0 to make the View focusable.
- * Currently, it is not possible to set this through props.
- * After the upgrade of 'react-native-web' to version 0.19 we can use 'tabIndex={0}' prop instead.
- */
- useEffect(() => {
- if (!ref.current) {
- return;
- }
- ref.current.setAttribute('tabindex', '0');
- }, []);
-
- return enabled ? (
- shouldEnableAutoFocus && ref.current,
- fallbackFocus: () => ref.current,
- clickOutsideDeactivates: true,
- }}
- >
-
-
- ) : (
- props.children
- );
-}
-
-FocusTrapView.displayName = 'FocusTrapView';
-FocusTrapView.propTypes = propTypes;
-FocusTrapView.defaultProps = defaultProps;
-
-export default FocusTrapView;
diff --git a/src/components/FocusTrapView/index.native.js b/src/components/FocusTrapView/index.native.js
deleted file mode 100644
index 5720601f5a2b..000000000000
--- a/src/components/FocusTrapView/index.native.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * The FocusTrap is only used on web and desktop
- */
-
-function FocusTrapView({children}) {
- return children;
-}
-
-FocusTrapView.displayName = 'FocusTrapView';
-
-export default FocusTrapView;
diff --git a/src/components/GrowlNotification/index.js b/src/components/GrowlNotification/index.js
index 70cadd5efd8e..a06185ac3320 100644
--- a/src/components/GrowlNotification/index.js
+++ b/src/components/GrowlNotification/index.js
@@ -10,6 +10,7 @@ import GrowlNotificationContainer from './GrowlNotificationContainer';
import CONST from '../../CONST';
import * as Growl from '../../libs/Growl';
import * as Pressables from '../Pressable';
+import useNativeDriver from '../../libs/useNativeDriver';
const types = {
[CONST.GROWL.SUCCESS]: {
@@ -59,7 +60,7 @@ function GrowlNotification(_, ref) {
Animated.spring(translateY, {
toValue: val,
duration: 80,
- useNativeDriver: true,
+ useNativeDriver,
}).start();
},
[translateY],
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/MagicCodeInput.js b/src/components/MagicCodeInput.js
index b21a275a6597..454aacc8a03b 100644
--- a/src/components/MagicCodeInput.js
+++ b/src/components/MagicCodeInput.js
@@ -258,7 +258,13 @@ function MagicCodeInput(props) {
{/* Hide the input above the text. Cannot set opacity to 0 as it would break pasting on iOS Safari. */}
(inputRefs.current[index] = ref)}
+ ref={(ref) => {
+ inputRefs.current[index] = ref;
+ // Setting attribute type to "search" to prevent Password Manager from appearing in Mobile Chrome
+ if (ref && ref.setAttribute) {
+ ref.setAttribute('type', 'search');
+ }
+ }}
autoFocus={index === 0 && props.autoFocus}
inputMode="numeric"
textContentType="oneTimeCode"
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/MapView/responder/index.android.ts b/src/components/MapView/responder/index.android.ts
new file mode 100644
index 000000000000..a0fce71d8ef5
--- /dev/null
+++ b/src/components/MapView/responder/index.android.ts
@@ -0,0 +1,8 @@
+import {PanResponder} from 'react-native';
+
+const responder = PanResponder.create({
+ onStartShouldSetPanResponder: () => true,
+ onPanResponderTerminationRequest: () => false,
+});
+
+export default responder;
diff --git a/src/components/MapView/responder/index.ts b/src/components/MapView/responder/index.ts
index a0fce71d8ef5..422d6c1b4963 100644
--- a/src/components/MapView/responder/index.ts
+++ b/src/components/MapView/responder/index.ts
@@ -1,7 +1,7 @@
import {PanResponder} from 'react-native';
const responder = PanResponder.create({
- onStartShouldSetPanResponder: () => true,
+ onMoveShouldSetPanResponder: () => true,
onPanResponderTerminationRequest: () => false,
});
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index c39c1d503258..bb4eeb7a18ac 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -1,6 +1,7 @@
import _ from 'underscore';
-import React from 'react';
+import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
+import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import Text from './Text';
import styles from '../styles/styles';
import themeColors from '../styles/themes/default';
@@ -23,6 +24,11 @@ import variables from '../styles/variables';
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;
@@ -33,6 +39,7 @@ const defaultProps = {
shouldShowBasicTitle: false,
shouldShowDescriptionOnTop: false,
shouldShowHeaderTitle: false,
+ shouldParseTitle: false,
wrapperStyle: [],
style: styles.popoverMenuItem,
titleStyle: {},
@@ -73,10 +80,12 @@ const defaultProps = {
title: '',
numberOfLinesTitle: 1,
shouldGreyOutWhenDisabled: true,
+ shouldRenderAsHTML: false,
};
const MenuItem = React.forwardRef((props, ref) => {
const {isSmallScreenWidth} = useWindowDimensions();
+ const [html, setHtml] = React.useState('');
const isDeleted = _.contains(props.style, styles.offlineFeedback.deleted);
const descriptionVerticalMargin = props.shouldShowDescriptionOnTop ? styles.mb1 : styles.mt1;
@@ -104,6 +113,28 @@ const MenuItem = React.forwardRef((props, ref) => {
const fallbackAvatarSize = props.viewMode === CONST.OPTION_MODE.COMPACT ? CONST.AVATAR_SIZE.SMALL : CONST.AVATAR_SIZE.DEFAULT;
+ const titleRef = React.useRef('');
+ useEffect(() => {
+ if (!props.title || (titleRef.current.length && titleRef.current === props.title) || !props.shouldParseTitle) {
+ return;
+ }
+ const parser = new ExpensiMark();
+ setHtml(parser.replace(convertToLTR(props.title)));
+ 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) => (
@@ -220,10 +251,20 @@ const MenuItem = React.forwardRef((props, ref) => {
)}
- {Boolean(props.title) && (
+ {Boolean(props.title) &&
+ (Boolean(props.shouldRenderAsHTML) || (Boolean(props.shouldParseTitle) && Boolean(html.length))) &&
+ (isNative ? (
+
+ ) : (
+
+
+
+ ))}
+ {!props.shouldRenderAsHTML && !html.length && Boolean(props.title) && (
{convertToLTR(props.title)}
diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js
index ab9d420f949c..051c4ba3f80a 100644
--- a/src/components/Modal/BaseModal.js
+++ b/src/components/Modal/BaseModal.js
@@ -1,4 +1,4 @@
-import React, {forwardRef, useCallback, useEffect, useMemo} from 'react';
+import React, {forwardRef, useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import ReactNativeModal from 'react-native-modal';
@@ -13,6 +13,8 @@ import useWindowDimensions from '../../hooks/useWindowDimensions';
import variables from '../../styles/variables';
import CONST from '../../CONST';
import ComposerFocusManager from '../../libs/ComposerFocusManager';
+import useNativeDriver from '../../libs/useNativeDriver';
+import usePrevious from '../../hooks/usePrevious';
const propTypes = {
...modalPropTypes,
@@ -40,7 +42,7 @@ function BaseModal({
fullscreen,
animationIn,
animationOut,
- useNativeDriver,
+ useNativeDriver: useNativeDriverProp,
hideModalContentWhileAnimating,
animationInTiming,
animationOutTiming,
@@ -54,6 +56,9 @@ function BaseModal({
const safeAreaInsets = useSafeAreaInsets();
+ const isVisibleRef = useRef(isVisible);
+ const wasVisible = usePrevious(isVisible);
+
/**
* Hides modal
* @param {Boolean} [callHideCallback=true] Should we call the onModalHide callback
@@ -75,20 +80,25 @@ function BaseModal({
);
useEffect(() => {
- 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);
},
@@ -187,7 +197,7 @@ function BaseModal({
deviceWidth={windowWidth}
animationIn={animationIn || modalStyleAnimationIn}
animationOut={animationOut || modalStyleAnimationOut}
- useNativeDriver={useNativeDriver}
+ useNativeDriver={useNativeDriverProp && useNativeDriver}
hideModalContentWhileAnimating={hideModalContentWhileAnimating}
animationInTiming={animationInTiming}
animationOutTiming={animationOutTiming}
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 da98d324681e..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 (
Navigation.navigate(ROUTES.getMoneyRequestDescriptionRoute(props.iouType, props.reportID))}
@@ -520,7 +528,7 @@ function MoneyRequestConfirmationList(props) {
disabled={didConfirm || props.isReadOnly}
/>
)}
- {canUseTags && !!tagList && (
+ {shouldShowTags && (
)}
+ {canUseTags && !lodashGet(props.policy, 'disabledFields.defaultBillable', true) && (
+
+ {translate('common.billable')}
+
+
+ )}
>
)}
@@ -561,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/MultipleAvatars.js b/src/components/MultipleAvatars.js
index 4c6ba1307fb7..916646b5619a 100644
--- a/src/components/MultipleAvatars.js
+++ b/src/components/MultipleAvatars.js
@@ -221,6 +221,7 @@ function MultipleAvatars(props) {
{`+${avatars.length - props.maxAvatarsInRow}`}
@@ -278,6 +279,7 @@ function MultipleAvatars(props) {
{`+${props.icons.length - 1}`}
diff --git a/src/components/NewDatePicker/CalendarPicker/index.js b/src/components/NewDatePicker/CalendarPicker/index.js
index fe0c36d32e41..1e1ef3c3fad3 100644
--- a/src/components/NewDatePicker/CalendarPicker/index.js
+++ b/src/components/NewDatePicker/CalendarPicker/index.js
@@ -130,7 +130,10 @@ class CalendarPicker extends React.PureComponent {
return (
-
+
this.setState({isYearPickerVisible: true})}
style={[styles.alignItemsCenter, styles.flexRow, styles.flex1, styles.justifyContentStart]}
@@ -186,6 +189,7 @@ class CalendarPicker extends React.PureComponent {
{dayOfWeek[0]}
@@ -212,6 +216,7 @@ class CalendarPicker extends React.PureComponent {
accessibilityLabel={day ? day.toString() : undefined}
focusable={Boolean(day)}
accessible={Boolean(day)}
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
{({hovered, pressed}) => (
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/Popover/index.js b/src/components/Popover/index.js
index bfd02ba1d3e3..a886fbbd0c6b 100644
--- a/src/components/Popover/index.js
+++ b/src/components/Popover/index.js
@@ -11,23 +11,41 @@ import PopoverWithoutOverlay from '../PopoverWithoutOverlay';
* On small screen widths, it uses BottomDocked modal type, and a Popover type on wide screen widths.
*/
function Popover(props) {
- if (!props.fullscreen && !props.isSmallScreenWidth) {
+ const {isVisible, onClose, isSmallScreenWidth, fullscreen, animationInTiming, onLayout, animationOutTiming, disableAnimation, withoutOverlay, anchorPosition} = props;
+
+ // Not adding this inside the PopoverProvider
+ // because this is an issue on smaller screens as well.
+ React.useEffect(() => {
+ const listener = () => {
+ if (!isVisible) {
+ return;
+ }
+
+ onClose();
+ };
+ window.addEventListener('popstate', listener);
+ return () => {
+ window.removeEventListener('popstate', listener);
+ };
+ }, [onClose, isVisible]);
+
+ if (!fullscreen && !isSmallScreenWidth) {
return createPortal(
,
document.body,
);
}
- if (props.withoutOverlay && !props.isSmallScreenWidth) {
+ if (withoutOverlay && !isSmallScreenWidth) {
// eslint-disable-next-line react/jsx-props-no-spreading
return createPortal(, document.body);
}
@@ -36,12 +54,12 @@ function Popover(props) {
);
}
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/GenericPressable/BaseGenericPressable.js b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
index 0c5b75b1bb13..9bb221b2de1e 100644
--- a/src/components/Pressable/GenericPressable/BaseGenericPressable.js
+++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
@@ -5,6 +5,7 @@ import _ from 'underscore';
import Accessibility from '../../../libs/Accessibility';
import HapticFeedback from '../../../libs/HapticFeedback';
import KeyboardShortcut from '../../../libs/KeyboardShortcut';
+import * as Browser from '../../../libs/Browser';
import styles from '../../../styles/styles';
import genericPressablePropTypes from './PropTypes';
import CONST from '../../../CONST';
@@ -127,13 +128,15 @@ const GenericPressable = forwardRef((props, ref) => {
return KeyboardShortcut.subscribe(shortcutKey, onPressHandler, descriptionKey, modifiers, true, false, 0, false);
}, [keyboardShortcut, onPressHandler]);
+ const defaultLongPressHandler = Browser.isMobileChrome() ? () => {} : undefined;
return (
(
aria-labelledby={props.accessibilityLabelledBy}
aria-valuenow={props.accessibilityValue}
nativeID={props.nativeID}
- dataSet={{tag: 'pressable', ...(props.noDragArea && {dragArea: false})}}
+ dataSet={{tag: 'pressable', ...(props.noDragArea && {dragArea: false}), ...props.dataSet}}
/>
));
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/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js
index 2771db6206ae..d84a3f282e97 100644
--- a/src/components/PressableWithSecondaryInteraction/index.js
+++ b/src/components/PressableWithSecondaryInteraction/index.js
@@ -1,103 +1,123 @@
import _ from 'underscore';
-import React, {Component} from 'react';
-import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes';
+import React, {forwardRef, useEffect, useRef} from 'react';
import styles from '../../styles/styles';
import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
import * as StyleUtils from '../../styles/StyleUtils';
import PressableWithFeedback from '../Pressable/PressableWithFeedback';
+import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes';
/**
* This is a special Pressable that calls onSecondaryInteraction when LongPressed, or right-clicked.
*/
-class PressableWithSecondaryInteraction extends Component {
- constructor(props) {
- super(props);
- this.executeSecondaryInteraction = this.executeSecondaryInteraction.bind(this);
- this.executeSecondaryInteractionOnContextMenu = this.executeSecondaryInteractionOnContextMenu.bind(this);
- }
-
- componentDidMount() {
- if (this.props.forwardedRef) {
- if (_.isFunction(this.props.forwardedRef)) {
- this.props.forwardedRef(this.pressableRef);
- } else if (_.isObject(this.props.forwardedRef)) {
- this.props.forwardedRef.current = this.pressableRef;
- }
- }
- this.pressableRef.addEventListener('contextmenu', this.executeSecondaryInteractionOnContextMenu);
- }
- componentWillUnmount() {
- this.pressableRef.removeEventListener('contextmenu', this.executeSecondaryInteractionOnContextMenu);
- }
+function PressableWithSecondaryInteraction({
+ children,
+ inline,
+ style,
+ enableLongPressWithHover,
+ withoutFocusOnSecondaryInteraction,
+ preventDefaultContextMenu,
+ onSecondaryInteraction,
+ onPressIn,
+ onPress,
+ onPressOut,
+ activeOpacity,
+ forwardedRef,
+ ...rest
+}) {
+ const pressableRef = useRef(null);
/**
* @param {Event} e - the secondary interaction event
*/
- executeSecondaryInteraction(e) {
- if (DeviceCapabilities.hasHoverSupport() && !this.props.enableLongPressWithHover) {
+ const executeSecondaryInteraction = (e) => {
+ if (DeviceCapabilities.hasHoverSupport() && !enableLongPressWithHover) {
return;
}
- if (this.props.withoutFocusOnSecondaryInteraction && this.pressableRef) {
- this.pressableRef.blur();
+ if (withoutFocusOnSecondaryInteraction && pressableRef.current) {
+ pressableRef.current.blur();
}
- this.props.onSecondaryInteraction(e);
- }
+ onSecondaryInteraction(e);
+ };
- /**
- * @param {contextmenu} e - A right-click MouseEvent.
- * https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event
- */
- executeSecondaryInteractionOnContextMenu(e) {
- if (!this.props.onSecondaryInteraction) {
+ useEffect(() => {
+ if (!pressableRef.current) {
return;
}
- e.stopPropagation();
- if (this.props.preventDefaultContextMenu) {
- e.preventDefault();
+ if (forwardedRef) {
+ if (_.isFunction(forwardedRef)) {
+ forwardedRef(pressableRef.current);
+ } else if (_.isObject(forwardedRef)) {
+ // eslint-disable-next-line no-param-reassign
+ forwardedRef.current = pressableRef.current;
+ }
}
- this.props.onSecondaryInteraction(e);
+ const element = pressableRef.current;
+
/**
- * This component prevents the tapped element from capturing focus.
- * We need to blur this element when clicked as it opens modal that implements focus-trapping.
- * When the modal is closed it focuses back to the last active element.
- * Therefore it shifts the element to bring it back to focus.
- * https://github.com/Expensify/App/issues/14148
+ * @param {contextmenu} e - A right-click MouseEvent.
+ * https://developer.mozilla.org/en-US/docs/Web/API/Element/contextmenu_event
*/
- if (this.props.withoutFocusOnSecondaryInteraction && this.pressableRef) {
- this.pressableRef.blur();
- }
- }
-
- render() {
- const defaultPressableProps = _.omit(this.props, ['onSecondaryInteraction', 'children', 'onLongPress']);
- const inlineStyle = this.props.inline ? styles.dInline : {};
-
- // On Web, Text does not support LongPress events thus manage inline mode with styling instead of using Text.
- return (
- (this.pressableRef = el)}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...defaultPressableProps}
- style={(state) => [StyleUtils.parseStyleFromFunction(this.props.style, state), inlineStyle]}
- >
- {this.props.children}
-
- );
- }
+ const executeSecondaryInteractionOnContextMenu = (e) => {
+ if (!onSecondaryInteraction) {
+ return;
+ }
+
+ e.stopPropagation();
+ if (preventDefaultContextMenu) {
+ e.preventDefault();
+ }
+
+ onSecondaryInteraction(e);
+
+ /**
+ * This component prevents the tapped element from capturing focus.
+ * We need to blur this element when clicked as it opens modal that implements focus-trapping.
+ * When the modal is closed it focuses back to the last active element.
+ * Therefore it shifts the element to bring it back to focus.
+ * https://github.com/Expensify/App/issues/14148
+ */
+ if (withoutFocusOnSecondaryInteraction) {
+ element.blur();
+ }
+ };
+
+ element.addEventListener('contextmenu', executeSecondaryInteractionOnContextMenu);
+
+ return () => {
+ element.removeEventListener('contextmenu', executeSecondaryInteractionOnContextMenu);
+ };
+ }, [forwardedRef, onSecondaryInteraction, preventDefaultContextMenu, withoutFocusOnSecondaryInteraction]);
+
+ const defaultPressableProps = _.omit(rest, ['onLongPress']);
+ const inlineStyle = inline ? styles.dInline : {};
+
+ // On Web, Text does not support LongPress events thus manage inline mode with styling instead of using Text.
+ return (
+ [StyleUtils.parseStyleFromFunction(style, state), inlineStyle]}
+ >
+ {children}
+
+ );
}
PressableWithSecondaryInteraction.propTypes = pressableWithSecondaryInteractionPropTypes.propTypes;
PressableWithSecondaryInteraction.defaultProps = pressableWithSecondaryInteractionPropTypes.defaultProps;
-export default React.forwardRef((props, ref) => (
+PressableWithSecondaryInteraction.displayName = 'PressableWithSecondaryInteraction';
+
+export default forwardRef((props, ref) => (
{
// 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/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js
index 922be96084d8..0315c63aabf1 100644
--- a/src/components/Reactions/AddReactionBubble.js
+++ b/src/components/Reactions/AddReactionBubble.js
@@ -94,6 +94,7 @@ function AddReactionBubble(props) {
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
// disable dimming
pressDimmingValue={1}
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
{({hovered, pressed}) => (
<>
diff --git a/src/components/Reactions/EmojiReactionBubble.js b/src/components/Reactions/EmojiReactionBubble.js
index bb37735d6920..818bc8f33309 100644
--- a/src/components/Reactions/EmojiReactionBubble.js
+++ b/src/components/Reactions/EmojiReactionBubble.js
@@ -60,6 +60,7 @@ function EmojiReactionBubble(props) {
styles.emojiReactionBubble,
StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, props.hasUserReacted, props.isContextMenu),
props.shouldBlockReactions && styles.cursorDisabled,
+ styles.userSelectNone,
]}
onPress={() => {
if (props.shouldBlockReactions) {
@@ -83,9 +84,10 @@ function EmojiReactionBubble(props) {
}}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
accessibilityLabel={props.emojiCodes.join('')}
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
- {props.emojiCodes.join('')}
- {props.count > 0 && {props.count}}
+ {props.emojiCodes.join('')}
+ {props.count > 0 && {props.count}}
);
}
diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js
index 82f83cb1e961..a22a2967cefe 100644
--- a/src/components/Reactions/MiniQuickEmojiReactions.js
+++ b/src/components/Reactions/MiniQuickEmojiReactions.js
@@ -80,7 +80,12 @@ function MiniQuickEmojiReactions(props) {
tooltipText={`:${EmojiUtils.getLocalizedEmojiName(emoji.name, props.preferredLocale)}:`}
onPress={Session.checkIfActionIsAllowed(() => props.onEmojiSelected(emoji, props.emojiReactions))}
>
- {EmojiUtils.getPreferredEmojiCode(emoji, props.preferredSkinTone)}
+
+ {EmojiUtils.getPreferredEmojiCode(emoji, props.preferredSkinTone)}
+
))}
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 a5a499169cbd..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 && (
<>
{requestMerchant}
)}
-
+
{!isCurrentUserManager && props.shouldShowPendingConversionMessage && (
- {props.translate('iou.pendingConversionMessage')}
+ {props.translate('iou.pendingConversionMessage')}
)}
- {shouldShowDescription && {description}}
+ {shouldShowDescription && {description}}
{props.isBillSplit && !_.isEmpty(participantAccountIDs) && (
-
+
{props.translate('iou.amountEach', {
amount: CurrencyUtils.convertToDisplayString(
IOUUtils.calculateAmount(isPolicyExpenseChat ? 1 : participantAccountIDs.length - 1, requestAmount, requestCurrency),
@@ -342,6 +339,7 @@ function MoneyRequestPreview(props) {
onLongPress={showContextMenu}
accessibilityLabel={props.isBillSplit ? props.translate('iou.split') : props.translate('iou.cash')}
accessibilityHint={CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency)}
+ style={[styles.moneyRequestPreviewBox, ...props.containerStyles]}
>
{childContainer}
diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js
index a9264812b99d..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);
@@ -105,6 +106,7 @@ function MoneyRequestView({report, parentReport, shouldShowHorizontalRule, trans
style={[StyleUtils.getReportWelcomeBackgroundImageStyle(true)]}
/>
+
{hasReceipt && (
Navigation.navigate(ROUTES.getEditRequestRoute(report.reportID, CONST.EDIT_REQUEST_FIELD.DESCRIPTION))}
+ wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]}
+ numberOfLinesTitle={0}
/>
@@ -165,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 1f60dddef6ec..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
@@ -177,7 +175,7 @@ function ReportPreview(props) {
onPressIn={() => DeviceCapabilities.canUseTouchScreen() && ControlSelection.block()}
onPressOut={() => ControlSelection.unblock()}
onLongPress={(event) => showContextMenuForReport(event, props.contextMenuAnchor, props.chatReportID, props.action, props.checkIfContextMenuActive)}
- style={[styles.flexRow, styles.justifyContentBetween]}
+ style={[styles.flexRow, styles.justifyContentBetween, styles.reportPreviewBox]}
accessibilityRole="button"
accessibilityLabel={props.translate('iou.viewDetails')}
>
@@ -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 965c3120d51b..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')}
@@ -119,6 +129,7 @@ function TaskView(props) {
Navigation.navigate(ROUTES.getTaskReportDescriptionRoute(props.report.reportID))}
@@ -127,6 +138,7 @@ function TaskView(props) {
wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]}
shouldGreyOutWhenDisabled={false}
numberOfLinesTitle={0}
+ interactive={!isDisableInteractive}
/>
{props.report.managerID ? (
@@ -144,6 +156,7 @@ function TaskView(props) {
wrapperStyle={[styles.pv2]}
isSmallAvatarSubscriptMenu
shouldGreyOutWhenDisabled={false}
+ interactive={!isDisableInteractive}
/>
) : (
@@ -154,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 && (
-
-
- {this.props.environment === CONST.ENVIRONMENT.DEV && }
- {this.props.environment === CONST.ENVIRONMENT.DEV && }
- {
- // If props.children is a function, call it to provide the insets to the children.
- _.isFunction(this.props.children)
- ? this.props.children({
- insets,
- safeAreaPaddingBottomStyle,
- didScreenTransitionEnd: this.state.didScreenTransitionEnd,
- })
- : this.props.children
- }
- {this.props.isSmallScreenWidth && this.props.shouldShowOfflineIndicator && }
-
+
+ {this.props.environment === CONST.ENVIRONMENT.DEV && }
+ {this.props.environment === CONST.ENVIRONMENT.DEV && }
+ {
+ // If props.children is a function, call it to provide the insets to the children.
+ _.isFunction(this.props.children)
+ ? this.props.children({
+ insets,
+ safeAreaPaddingBottomStyle,
+ didScreenTransitionEnd: this.state.didScreenTransitionEnd,
+ })
+ : this.props.children
+ }
+ {this.props.isSmallScreenWidth && this.props.shouldShowOfflineIndicator && }
diff --git a/src/components/ScreenWrapper/propTypes.js b/src/components/ScreenWrapper/propTypes.js
index c3538b3c026d..83033d9e97b7 100644
--- a/src/components/ScreenWrapper/propTypes.js
+++ b/src/components/ScreenWrapper/propTypes.js
@@ -48,12 +48,6 @@ const propTypes = {
/** Styles for the offline indicator */
offlineIndicatorStyle: stylePropTypes,
-
- /** Whether to disable the focus trap */
- shouldDisableFocusTrap: PropTypes.bool,
-
- /** Whether to disable auto focus of the focus trap */
- shouldEnableAutoFocus: PropTypes.bool,
};
const defaultProps = {
@@ -69,8 +63,6 @@ const defaultProps = {
shouldShowOfflineIndicator: true,
offlineIndicatorStyle: [],
headerGapStyles: [],
- shouldDisableFocusTrap: false,
- shouldEnableAutoFocus: false,
};
export {propTypes, defaultProps};
diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js
index 2a1bca24ab74..e57f00e1849c 100644
--- a/src/components/SelectionList/BaseSelectionList.js
+++ b/src/components/SelectionList/BaseSelectionList.js
@@ -348,6 +348,7 @@ function BaseSelectionList({
accessibilityRole="button"
accessibilityState={{checked: flattenedSections.allSelected}}
disabled={flattenedSections.allOptions.length === flattenedSections.disabledOptionsIndexes.length}
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
diff --git a/src/components/SelectionList/UserListItem.js b/src/components/SelectionList/UserListItem.js
index a3c25f09af3b..014e0cf879a5 100644
--- a/src/components/SelectionList/UserListItem.js
+++ b/src/components/SelectionList/UserListItem.js
@@ -63,6 +63,7 @@ function UserListItem({item, isFocused = false, showTooltip, onSelectRow, onDism
hoverDimmingValue={1}
hoverStyle={styles.hoveredComponentBG}
focusStyle={styles.hoveredComponentBG}
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
(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/Switch.js b/src/components/Switch.js
index 3b7f464b00e5..5c8a0da925f3 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -4,6 +4,7 @@ import {Animated} from 'react-native';
import CONST from '../CONST';
import styles from '../styles/styles';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
+import useNativeDriver from '../libs/useNativeDriver';
const propTypes = {
/** Whether the switch is toggled to the on position */
@@ -28,7 +29,7 @@ function Switch(props) {
Animated.timing(offsetX.current, {
toValue: props.isOn ? OFFSET_X.ON : OFFSET_X.OFF,
duration: 300,
- useNativeDriver: true,
+ useNativeDriver,
}).start();
}, [props.isOn]);
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/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 9d122fb7ccf1..ec22b09dde04 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -20,6 +20,7 @@ import FormHelpMessage from '../FormHelpMessage';
import isInputAutoFilled from '../../libs/isInputAutoFilled';
import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
import withLocalize from '../withLocalize';
+import useNativeDriver from '../../libs/useNativeDriver';
function BaseTextInput(props) {
const inputValue = props.value || props.defaultValue || '';
@@ -85,12 +86,12 @@ function BaseTextInput(props) {
Animated.spring(labelTranslateY, {
toValue: translateY,
duration: styleConst.LABEL_ANIMATION_DURATION,
- useNativeDriver: true,
+ useNativeDriver,
}),
Animated.spring(labelScale, {
toValue: scale,
duration: styleConst.LABEL_ANIMATION_DURATION,
- useNativeDriver: true,
+ useNativeDriver,
}),
]).start();
},
@@ -305,6 +306,7 @@ function BaseTextInput(props) {
pointerEvents="none"
selectable={false}
style={[styles.textInputPrefix, !hasLabel && styles.pv0]}
+ dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
>
{props.prefixCharacter}
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/menuItemPropTypes.js b/src/components/menuItemPropTypes.js
index cc89f9a7b80b..53216ab7cdc7 100644
--- a/src/components/menuItemPropTypes.js
+++ b/src/components/menuItemPropTypes.js
@@ -144,6 +144,9 @@ const propTypes = {
/** Should we grey out the menu item when it is disabled? */
shouldGreyOutWhenDisabled: PropTypes.bool,
+
+ /** Should render the content in HTML format */
+ shouldRenderAsHTML: PropTypes.bool,
};
export default propTypes;
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/withCurrentUserPersonalDetails.js b/src/components/withCurrentUserPersonalDetails.js
index 87a046e66983..7a47ea7cc712 100644
--- a/src/components/withCurrentUserPersonalDetails.js
+++ b/src/components/withCurrentUserPersonalDetails.js
@@ -36,7 +36,8 @@ export default function (WrappedComponent) {
function WithCurrentUserPersonalDetails(props) {
const accountID = props.session.accountID;
- const currentUserPersonalDetails = useMemo(() => ({...props.personalDetails[accountID], accountID}), [props.personalDetails, accountID]);
+ const accountPersonalDetails = props.personalDetails[accountID];
+ const currentUserPersonalDetails = useMemo(() => ({...accountPersonalDetails, accountID}), [accountPersonalDetails, accountID]);
return (
true,
- addListener: () => () => {},
- removeListener: () => () => {},
- }}
- >
-
-
- );
- }
+ function WithNavigationFallback(props) {
+ const context = useContext(NavigationContext);
- return (
+ const navigationContextValue = useMemo(() => ({isFocused: () => true, addListener: () => () => {}, removeListener: () => () => {}}), []);
+
+ return context ? (
+
+ ) : (
+
- );
- }
+
+ );
}
- WithNavigationFallback.contextType = NavigationContext;
WithNavigationFallback.displayName = `WithNavigationFocusWithFallback(${getComponentDisplayName(WrappedComponent)})`;
WithNavigationFallback.propTypes = {
forwardedRef: refPropTypes,
@@ -41,7 +32,8 @@ export default function (WrappedComponent) {
WithNavigationFallback.defaultProps = {
forwardedRef: undefined,
};
- return React.forwardRef((props, ref) => (
+
+ return forwardRef((props, ref) => (
{
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/hooks/usePrivatePersonalDetails.js b/src/hooks/usePrivatePersonalDetails.js
index 37eb63dcd0fd..14c1e42e629a 100644
--- a/src/hooks/usePrivatePersonalDetails.js
+++ b/src/hooks/usePrivatePersonalDetails.js
@@ -1,4 +1,5 @@
import {useEffect, useContext} from 'react';
+import _ from 'underscore';
import * as PersonalDetails from '../libs/actions/PersonalDetails';
import {NetworkContext} from '../components/OnyxProvider';
@@ -9,7 +10,8 @@ export default function usePrivatePersonalDetails() {
const {isOffline} = useContext(NetworkContext);
useEffect(() => {
- if (isOffline || Boolean(PersonalDetails.getPrivatePersonalDetails())) {
+ const personalDetails = PersonalDetails.getPrivatePersonalDetails();
+ if (isOffline || (Boolean(personalDetails) && !_.isUndefined(personalDetails.isLoading))) {
return;
}
PersonalDetails.openPersonalDetailsPage();
diff --git a/src/hooks/useWindowDimensions/index.js b/src/hooks/useWindowDimensions/index.js
index 86ff7ce85d3d..1a1f7eed5a67 100644
--- a/src/hooks/useWindowDimensions/index.js
+++ b/src/hooks/useWindowDimensions/index.js
@@ -1,5 +1,5 @@
// eslint-disable-next-line no-restricted-imports
-import {useWindowDimensions} from 'react-native';
+import {Dimensions, useWindowDimensions} from 'react-native';
import variables from '../../styles/variables';
/**
@@ -8,7 +8,9 @@ import variables from '../../styles/variables';
*/
export default function () {
const {width: windowWidth, height: windowHeight} = useWindowDimensions();
- const isExtraSmallScreenHeight = windowHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint;
+ // When the soft keyboard opens on mWeb, the window height changes. Use static screen height instead to get real screenHeight.
+ const screenHeight = Dimensions.get('screen').height;
+ const isExtraSmallScreenHeight = screenHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint;
const isSmallScreenWidth = windowWidth <= variables.mobileResponsiveWidthBreakpoint;
const isMediumScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint && windowWidth <= variables.tabletResponsiveWidthBreakpoint;
const isLargeScreenWidth = windowWidth > variables.tabletResponsiveWidthBreakpoint;
diff --git a/src/languages/en.ts b/src/languages/en.ts
index e47ae06b108f..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',
@@ -344,11 +346,6 @@ export default {
`It's always great to see a new face around here! Please enter the magic code sent to ${login}. It should arrive within a minute or two.`,
welcomeEnterMagicCode: ({login}: WelcomeEnterMagicCodeParams) => `Please enter the magic code sent to ${login}. It should arrive within a minute or two.`,
},
- DownloadAppModal: {
- downloadTheApp: 'Download the app',
- keepTheConversationGoing: 'Keep the conversation going in New Expensify, download the app for an enhanced experience.',
- noThanks: 'No thanks',
- },
login: {
hero: {
header: 'Split bills, request payments, and chat with friends.',
@@ -518,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}`,
@@ -534,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',
@@ -548,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',
@@ -573,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) =>
@@ -592,6 +590,7 @@ export default {
online: 'Online',
offline: 'Offline',
syncing: 'Syncing',
+ profileAvatar: 'Profile avatar',
},
loungeAccessPage: {
loungeAccess: 'Lounge access',
@@ -733,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',
@@ -744,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',
@@ -754,17 +763,13 @@ export default {
passwordUpdated: 'Password updated!',
allSet: 'You’re all set. Keep your new password safe.',
},
- 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',
+ privateNotes: {
+ title: 'Private notes',
+ personalNoteMessage: 'Keep notes about this chat here. You are the only person who can add, edit or view these notes.',
+ 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',
+ myNote: 'My note',
},
addDebitCardPage: {
addADebitCard: 'Add a debit card',
@@ -795,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.',
@@ -902,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',
@@ -1314,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',
@@ -1522,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.',
},
@@ -1694,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 2b345daded2f..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',
@@ -335,11 +337,6 @@ export default {
`¡Siempre es genial ver una cara nueva por aquí! Por favor ingresa el código mágico enviado a ${login}. Debería llegar en un par de minutos.`,
welcomeEnterMagicCode: ({login}: WelcomeEnterMagicCodeParams) => `Por favor, introduce el código mágico enviado a ${login}. Debería llegar en un par de minutos.`,
},
- DownloadAppModal: {
- downloadTheApp: 'Descarga la aplicación',
- keepTheConversationGoing: 'Mantén la conversación en New Expensify, descarga la aplicación para una experiencia mejorada.',
- noThanks: 'No, gracias',
- },
login: {
hero: {
header: 'Divida las facturas, solicite pagos y chatee con sus amigos.',
@@ -510,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}`,
@@ -526,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',
@@ -541,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',
@@ -566,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) =>
@@ -585,6 +583,7 @@ export default {
online: 'En línea',
offline: 'Desconectado',
syncing: 'Sincronizando',
+ profileAvatar: 'Perfil avatar',
},
loungeAccessPage: {
loungeAccess: 'Acceso a la sala vip',
@@ -728,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',
@@ -739,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',
@@ -749,17 +758,13 @@ export default {
passwordUpdated: 'Contraseña actualizada!',
allSet: 'Todo está listo. Guarda tu contraseña en un lugar seguro.',
},
- 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',
+ privateNotes: {
+ title: 'Notas privadas',
+ personalNoteMessage: 'Guarda notas sobre este chat aquí. Usted es la única persona que puede añadir, editar o ver estas notas.',
+ 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',
+ myNote: 'Mi notas',
},
addDebitCardPage: {
addADebitCard: 'Añadir una tarjeta de débito',
@@ -790,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.',
@@ -898,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',
@@ -1333,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',
@@ -1544,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.',
},
@@ -2176,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/CardUtils.ts b/src/libs/CardUtils.ts
index bbb938a666ac..beb0ea800091 100644
--- a/src/libs/CardUtils.ts
+++ b/src/libs/CardUtils.ts
@@ -1,3 +1,6 @@
+import {Card} from '../types/onyx';
+import CONST from '../CONST';
+
/**
* @returns string with a month in MM format
*/
@@ -15,4 +18,11 @@ function getYearFromExpirationDateString(expirationDateString: string) {
return cardYear.length === 2 ? `20${cardYear}` : cardYear;
}
-export {getMonthFromExpirationDateString, getYearFromExpirationDateString};
+function getCompanyCards(cardList: {string: Card}) {
+ if (!cardList) {
+ return [];
+ }
+ return Object.values(cardList).filter((card) => card.bank !== CONST.EXPENSIFY_CARD.BANK);
+}
+
+export {getMonthFromExpirationDateString, getYearFromExpirationDateString, getCompanyCards};
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/LocalePhoneNumber.js b/src/libs/LocalePhoneNumber.ts
similarity index 82%
rename from src/libs/LocalePhoneNumber.js
rename to src/libs/LocalePhoneNumber.ts
index e5c7cbfa45ba..962040aee049 100644
--- a/src/libs/LocalePhoneNumber.js
+++ b/src/libs/LocalePhoneNumber.ts
@@ -3,20 +3,17 @@ import Str from 'expensify-common/lib/str';
import {parsePhoneNumber} from 'awesome-phonenumber';
import ONYXKEYS from '../ONYXKEYS';
-let countryCodeByIP;
+let countryCodeByIP: number;
Onyx.connect({
key: ONYXKEYS.COUNTRY_CODE,
- callback: (val) => (countryCodeByIP = val || 1),
+ callback: (val) => (countryCodeByIP = val ?? 1),
});
/**
* Returns a locally converted phone number for numbers from the same region
* and an internationally converted phone number with the country code for numbers from other regions
- *
- * @param {String} number
- * @returns {String}
*/
-function formatPhoneNumber(number) {
+function formatPhoneNumber(number: string): string {
if (!number) {
return '';
}
@@ -26,7 +23,7 @@ function formatPhoneNumber(number) {
// return the string untouched if it's not a phone number
if (!parsedPhoneNumber.valid) {
- if (parsedPhoneNumber.number && parsedPhoneNumber.number.international) {
+ if (parsedPhoneNumber.number?.international) {
return parsedPhoneNumber.number.international;
}
return numberWithoutSMSDomain;
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 ea9ef0840812..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: () => {
@@ -760,6 +753,30 @@ const EditRequestStackNavigator = createModalStackNavigator([
},
]);
+const PrivateNotesModalStackNavigator = createModalStackNavigator([
+ {
+ getComponent: () => {
+ const PrivateNotesPage = require('../../../pages/PrivateNotes/PrivateNotesViewPage').default;
+ return PrivateNotesPage;
+ },
+ name: 'PrivateNotes_View',
+ },
+ {
+ getComponent: () => {
+ const PrivateNotesListPage = require('../../../pages/PrivateNotes/PrivateNotesListPage').default;
+ return PrivateNotesListPage;
+ },
+ name: 'PrivateNotes_List',
+ },
+ {
+ getComponent: () => {
+ const PrivateNotesEditPage = require('../../../pages/PrivateNotes/PrivateNotesEditPage').default;
+ return PrivateNotesEditPage;
+ },
+ name: 'PrivateNotes_Edit',
+ },
+]);
+
const SignInModalStackNavigator = createModalStackNavigator([
{
getComponent: () => {
@@ -790,6 +807,7 @@ export {
WalletStatementStackNavigator,
FlagCommentStackNavigator,
EditRequestStackNavigator,
+ PrivateNotesModalStackNavigator,
NewTeachersUniteNavigator,
SignInModalStackNavigator,
};
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
index 1340c4bb8e62..27a15fa3d763 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
@@ -108,6 +108,10 @@ function RightModalNavigator(props) {
name="SignIn"
component={ModalStackNavigators.SignInModalStackNavigator}
/>
+
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/OnyxTabNavigator.js b/src/libs/Navigation/OnyxTabNavigator.js
index dc68021bf515..2782054497b0 100644
--- a/src/libs/Navigation/OnyxTabNavigator.js
+++ b/src/libs/Navigation/OnyxTabNavigator.js
@@ -33,6 +33,7 @@ function OnyxTabNavigator({id, selectedTab, children, ...rest}) {
id={id}
initialRouteName={selectedTab}
backBehavior="initialRoute"
+ keyboardDismissMode="none"
screenListeners={{
state: (event) => {
const state = event.data.state;
diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js
index 3311fc81bc82..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,
},
@@ -213,6 +209,13 @@ export default {
},
},
},
+ Private_Notes: {
+ screens: {
+ PrivateNotes_View: ROUTES.PRIVATE_NOTES_VIEW,
+ PrivateNotes_List: ROUTES.PRIVATE_NOTES_LIST,
+ PrivateNotes_Edit: ROUTES.PRIVATE_NOTES_EDIT,
+ },
+ },
Report_Details: {
screens: {
Report_Details_Root: ROUTES.REPORT_WITH_ID_DETAILS,
@@ -270,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
- {props.translate('genericErrorPage.title')}
+ {translate('genericErrorPage.title')}
- {`${props.translate('genericErrorPage.body.helpTextConcierge')} `}
+ {`${translate('genericErrorPage.body.helpTextConcierge')} `}
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
new file mode 100644
index 000000000000..206e9e74d91f
--- /dev/null
+++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js
@@ -0,0 +1,157 @@
+import React, {useState, useRef} from 'react';
+import PropTypes from 'prop-types';
+import {View, Keyboard} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import lodashGet from 'lodash/get';
+import Str from 'expensify-common/lib/str';
+import ExpensiMark from 'expensify-common/lib/ExpensiMark';
+import _ from 'underscore';
+import withLocalize from '../../components/withLocalize';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import HeaderWithBackButton from '../../components/HeaderWithBackButton';
+import Navigation from '../../libs/Navigation/Navigation';
+import styles from '../../styles/styles';
+import compose from '../../libs/compose';
+import ONYXKEYS from '../../ONYXKEYS';
+import TextInput from '../../components/TextInput';
+import CONST from '../../CONST';
+import Text from '../../components/Text';
+import Form from '../../components/Form';
+import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
+import reportPropTypes from '../reportPropTypes';
+import personalDetailsPropType from '../personalDetailsPropType';
+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 */
+ personalDetailsList: PropTypes.objectOf(personalDetailsPropType),
+
+ /** The report currently being looked at */
+ report: reportPropTypes,
+ route: PropTypes.shape({
+ /** Params from the URL path */
+ params: PropTypes.shape({
+ /** reportID and accountID passed via route: /r/:reportID/notes */
+ reportID: PropTypes.string,
+ accountID: PropTypes.string,
+ }),
+ }).isRequired,
+
+ /** Session of currently logged in user */
+ session: PropTypes.shape({
+ /** Currently logged in user accountID */
+ accountID: PropTypes.number,
+ }),
+};
+
+const defaultProps = {
+ report: {},
+ session: {
+ accountID: null,
+ },
+ personalDetailsList: {},
+};
+
+function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
+ const {translate} = useLocalize();
+
+ // We need to edit the note in markdown format, but display it in HTML format
+ const parser = new ExpensiMark();
+ const [privateNote, setPrivateNote] = useState(parser.htmlToMarkdown(lodashGet(report, ['privateNotes', route.params.accountID, 'note'], '')).trim());
+ const isCurrentUserNote = Number(session.accountID) === Number(route.params.accountID);
+
+ // To focus on the input field when the page loads
+ const privateNotesInput = useRef(null);
+
+ const savePrivateNote = () => {
+ const editedNote = parser.replace(privateNote);
+ Report.updatePrivateNotes(report.reportID, route.params.accountID, editedNote);
+ Keyboard.dismiss();
+
+ // Take user back to the PrivateNotesView page
+ Navigation.goBack(ROUTES.HOME);
+ };
+
+ return (
+ focusAndUpdateMultilineInputRange(privateNotesInput.current)}
+ >
+
+ Navigation.dismissModal()}
+ />
+
+
+
+ {translate(
+ Str.extractEmailDomain(lodashGet(personalDetailsList, [route.params.accountID, 'login'], '')) === CONST.EMAIL.GUIDES_DOMAIN
+ ? 'privateNotes.sharedNoteMessage'
+ : 'privateNotes.personalNoteMessage',
+ )}
+
+
+
+
+
+
+ );
+}
+
+PrivateNotesEditPage.displayName = 'PrivateNotesEditPage';
+PrivateNotesEditPage.propTypes = propTypes;
+PrivateNotesEditPage.defaultProps = defaultProps;
+
+export default compose(
+ withLocalize,
+ withOnyx({
+ report: {
+ key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`,
+ },
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ personalDetailsList: {
+ key: ONYXKEYS.PERSONAL_DETAILS_LIST,
+ },
+ }),
+)(PrivateNotesEditPage);
diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.js b/src/pages/PrivateNotes/PrivateNotesListPage.js
new file mode 100644
index 000000000000..098bfd2a245b
--- /dev/null
+++ b/src/pages/PrivateNotes/PrivateNotesListPage.js
@@ -0,0 +1,154 @@
+import React, {useMemo, useEffect} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import PropTypes from 'prop-types';
+import _ from 'underscore';
+import lodashGet from 'lodash/get';
+import Navigation from '../../libs/Navigation/Navigation';
+import ONYXKEYS from '../../ONYXKEYS';
+import CONST from '../../CONST';
+import styles from '../../styles/styles';
+import compose from '../../libs/compose';
+import OfflineWithFeedback from '../../components/OfflineWithFeedback';
+import MenuItem from '../../components/MenuItem';
+import useLocalize from '../../hooks/useLocalize';
+import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
+import * as Report from '../../libs/actions/Report';
+import personalDetailsPropType from '../personalDetailsPropType';
+import * as UserUtils from '../../libs/UserUtils';
+import reportPropTypes from '../reportPropTypes';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '../../components/HeaderWithBackButton';
+import {withNetwork} from '../../components/OnyxProvider';
+import networkPropTypes from '../../components/networkPropTypes';
+import ROUTES from '../../ROUTES';
+
+const propTypes = {
+ /** The report currently being looked at */
+ report: reportPropTypes,
+ route: PropTypes.shape({
+ /** Params from the URL path */
+ params: PropTypes.shape({
+ /** reportID and accountID passed via route: /r/:reportID/notes */
+ reportID: PropTypes.string,
+ accountID: PropTypes.string,
+ }),
+ }).isRequired,
+
+ /** Session info for the currently logged in user. */
+ session: PropTypes.shape({
+ /** Currently logged in user accountID */
+ accountID: PropTypes.number,
+ }),
+
+ /** All of the personal details for everyone */
+ personalDetailsList: PropTypes.objectOf(personalDetailsPropType),
+
+ /** Information about the network */
+ network: networkPropTypes.isRequired,
+ ...withLocalizePropTypes,
+};
+
+const defaultProps = {
+ report: {},
+ session: {
+ accountID: null,
+ },
+ personalDetailsList: {},
+};
+
+function PrivateNotesListPage({report, personalDetailsList, network, session}) {
+ const {translate} = useLocalize();
+
+ useEffect(() => {
+ if (network.isOffline) {
+ return;
+ }
+ Report.getReportPrivateNote(report.reportID);
+ }, [report.reportID, network.isOffline]);
+
+ /**
+ * Gets the menu item for each workspace
+ *
+ * @param {Object} item
+ * @param {Number} index
+ * @returns {JSX}
+ */
+ function getMenuItem(item, index) {
+ const keyTitle = item.translationKey ? translate(item.translationKey) : item.title;
+
+ return (
+
+
+
+ );
+ }
+
+ /**
+ * Returns a list of private notes on the given chat report
+ * @returns {Array} the menu item list
+ */
+ const privateNotes = useMemo(() => {
+ 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) ? 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, translate]);
+
+ return (
+
+
+ Navigation.dismissModal()}
+ />
+ {report.isLoadingPrivateNotes && _.isEmpty(lodashGet(report, 'privateNotes', {})) ? (
+
+ ) : (
+ _.map(privateNotes, (item, index) => getMenuItem(item, index))
+ )}
+
+
+ );
+}
+
+PrivateNotesListPage.propTypes = propTypes;
+PrivateNotesListPage.defaultProps = defaultProps;
+
+export default compose(
+ withLocalize,
+ withOnyx({
+ report: {
+ key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`,
+ },
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ personalDetailsList: {
+ key: ONYXKEYS.PERSONAL_DETAILS_LIST,
+ },
+ }),
+ withNetwork(),
+)(PrivateNotesListPage);
diff --git a/src/pages/PrivateNotes/PrivateNotesViewPage.js b/src/pages/PrivateNotes/PrivateNotesViewPage.js
new file mode 100644
index 000000000000..48f053f10f90
--- /dev/null
+++ b/src/pages/PrivateNotes/PrivateNotesViewPage.js
@@ -0,0 +1,107 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import {ScrollView} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import lodashGet from 'lodash/get';
+import _ from 'underscore';
+import withLocalize from '../../components/withLocalize';
+import ScreenWrapper from '../../components/ScreenWrapper';
+import HeaderWithBackButton from '../../components/HeaderWithBackButton';
+import Navigation from '../../libs/Navigation/Navigation';
+import styles from '../../styles/styles';
+import compose from '../../libs/compose';
+import ONYXKEYS from '../../ONYXKEYS';
+import ROUTES from '../../ROUTES';
+import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
+import reportPropTypes from '../reportPropTypes';
+import personalDetailsPropType from '../personalDetailsPropType';
+import useLocalize from '../../hooks/useLocalize';
+import OfflineWithFeedback from '../../components/OfflineWithFeedback';
+import MenuItemWithTopDescription from '../../components/MenuItemWithTopDescription';
+import CONST from '../../CONST';
+
+const propTypes = {
+ /** All of the personal details for everyone */
+ personalDetailsList: PropTypes.objectOf(personalDetailsPropType),
+
+ /** The report currently being looked at */
+ report: reportPropTypes,
+ route: PropTypes.shape({
+ /** Params from the URL path */
+ params: PropTypes.shape({
+ /** reportID and accountID passed via route: /r/:reportID/notes */
+ reportID: PropTypes.string,
+ accountID: PropTypes.string,
+ }),
+ }).isRequired,
+
+ /** Session of currently logged in user */
+ session: PropTypes.shape({
+ /** Currently logged in user accountID */
+ accountID: PropTypes.number,
+ }),
+};
+
+const defaultProps = {
+ report: {},
+ session: {
+ accountID: null,
+ },
+ personalDetailsList: {},
+};
+
+function PrivateNotesViewPage({route, personalDetailsList, session, report}) {
+ const {translate} = useLocalize();
+ const isCurrentUserNote = Number(session.accountID) === Number(route.params.accountID);
+ const privateNote = lodashGet(report, ['privateNotes', route.params.accountID, 'note'], '');
+
+ return (
+
+
+ Navigation.dismissModal()}
+ />
+
+
+ isCurrentUserNote && Navigation.navigate(ROUTES.getPrivateNotesEditRoute(report.reportID, route.params.accountID))}
+ shouldShowRightIcon={isCurrentUserNote}
+ numberOfLinesTitle={0}
+ shouldRenderAsHTML
+ brickRoadIndicator={!_.isEmpty(lodashGet(report, ['privateNotes', route.params.accountID, 'errors'], '')) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
+ disabled={!isCurrentUserNote}
+ shouldGreyOutWhenDisabled={false}
+ />
+
+
+
+
+ );
+}
+
+PrivateNotesViewPage.displayName = 'PrivateNotesViewPage';
+PrivateNotesViewPage.propTypes = propTypes;
+PrivateNotesViewPage.defaultProps = defaultProps;
+
+export default compose(
+ withLocalize,
+ withOnyx({
+ report: {
+ key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID.toString()}`,
+ },
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ personalDetailsList: {
+ key: ONYXKEYS.PERSONAL_DETAILS_LIST,
+ },
+ }),
+)(PrivateNotesViewPage);
diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js
index 22cac40cf29c..b515da04b7be 100755
--- a/src/pages/ProfilePage.js
+++ b/src/pages/ProfilePage.js
@@ -36,6 +36,7 @@ import * as Illustrations from '../components/Icon/Illustrations';
import variables from '../styles/variables';
import * as ValidationUtils from '../libs/ValidationUtils';
import Permissions from '../libs/Permissions';
+import ROUTES from '../ROUTES';
const matchType = PropTypes.shape({
params: PropTypes.shape({
@@ -138,10 +139,12 @@ 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;
return (
-
+
Navigation.goBack(navigateBackTo)}
@@ -235,6 +238,17 @@ function ProfilePage(props) {
shouldShowRightIcon
/>
)}
+ {!_.isEmpty(chatReportWithCurrentUser) && (
+
+ {!_.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..b9ee016d4099 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();
@@ -62,7 +63,19 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
setHeaderTitle(_.isEmpty(iou.participants) ? translate('tabSelector.manual') : translate('iou.split'));
}, [iou.participants, isDistanceRequest, translate]);
- const navigateToNextStep = (moneyRequestType) => {
+ const navigateToRequestStep = (moneyRequestType, option) => {
+ if (option.reportID) {
+ isNewReportIDSelectedLocally.current = true;
+ IOU.setMoneyRequestId(`${moneyRequestType}${option.reportID}`);
+ Navigation.navigate(ROUTES.getMoneyRequestConfirmationRoute(moneyRequestType, option.reportID));
+ return;
+ }
+
+ IOU.setMoneyRequestId(moneyRequestType);
+ Navigation.navigate(ROUTES.getMoneyRequestConfirmationRoute(moneyRequestType, reportID.current));
+ };
+
+ const navigateToSplitStep = (moneyRequestType) => {
IOU.setMoneyRequestId(moneyRequestType);
Navigation.navigate(ROUTES.getMoneyRequestConfirmationRoute(moneyRequestType, reportID.current));
};
@@ -112,11 +125,12 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
ref={(el) => (optionsSelectorRef.current = el)}
participants={iou.participants}
onAddParticipants={IOU.setMoneyRequestParticipants}
- navigateToRequest={() => navigateToNextStep(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)}
- navigateToSplit={() => navigateToNextStep(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)}
+ navigateToRequest={(option) => navigateToRequestStep(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, option)}
+ navigateToSplit={() => navigateToSplitStep(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)}
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..170ee042bffa 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,8 +158,10 @@ function MoneyRequestParticipantsSelector({
* @param {Object} option
*/
const addSingleParticipant = (option) => {
- onAddParticipants([{accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true}]);
- navigateToRequest();
+ onAddParticipants([
+ {accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true, searchText: option.searchText},
+ ]);
+ navigateToRequest(option);
};
/**
@@ -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
@@ -115,7 +115,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) {
IOU.resetMoneyRequestInfo(moneyRequestID);
}
- if (!isDistanceRequestTab && (_.isEmpty(iou.participants) || iou.amount === 0 || shouldReset)) {
+ if (!isDistanceRequestTab && (_.isEmpty(iou.participantAccountIDs) || iou.amount === 0 || shouldReset)) {
Navigation.goBack(ROUTES.getMoneyRequestRoute(iouType, reportID), true);
}
}
@@ -123,10 +123,10 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) {
return () => {
prevMoneyRequestID.current = iou.id;
};
- }, [iou.participants, iou.amount, iou.id, isEditing, iouType, reportID, isDistanceRequestTab]);
+ }, [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/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()}
/>