diff --git a/android/app/build.gradle b/android/app/build.gradle index 18ef2984f67a..38ba58bb6a86 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -98,8 +98,8 @@ android { minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion multiDexEnabled rootProject.ext.multiDexEnabled - versionCode 1001042500 - versionName "1.4.25-0" + versionCode 1001042505 + versionName "1.4.25-5" } flavorDimensions "default" diff --git a/android/app/src/main/res/drawable/ic_launcher_monochrome.png b/android/app/src/main/res/drawable/ic_launcher_monochrome.png index b1a286b6f8dd..0af99b087923 100644 Binary files a/android/app/src/main/res/drawable/ic_launcher_monochrome.png and b/android/app/src/main/res/drawable/ic_launcher_monochrome.png differ diff --git a/assets/images/expensify-logo--adhoc.svg b/assets/images/expensify-logo--adhoc.svg index 273002deca9b..52b381dc4b78 100644 --- a/assets/images/expensify-logo--adhoc.svg +++ b/assets/images/expensify-logo--adhoc.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/assets/images/expensify-logo--dev.svg b/assets/images/expensify-logo--dev.svg index e8e3fb5033d9..2c9ae142e283 100644 --- a/assets/images/expensify-logo--dev.svg +++ b/assets/images/expensify-logo--dev.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/assets/images/expensify-logo--staging.svg b/assets/images/expensify-logo--staging.svg index 78dcc1581f99..a1e7482c133b 100644 --- a/assets/images/expensify-logo--staging.svg +++ b/assets/images/expensify-logo--staging.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/assets/images/home-background--mobile-new.svg b/assets/images/home-background--mobile-new.svg index 0da937cae059..d81f2a18cc78 100644 --- a/assets/images/home-background--mobile-new.svg +++ b/assets/images/home-background--mobile-new.svg @@ -1,8835 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/new-expensify.svg b/assets/images/new-expensify.svg index 89102ecbc5e4..7bfef1fd38b4 100644 --- a/assets/images/new-expensify.svg +++ b/assets/images/new-expensify.svg @@ -1 +1 @@ - + \ No newline at end of file diff --git a/assets/images/product-illustrations/telescope.svg b/assets/images/product-illustrations/telescope.svg index 95617c801789..1830dff0fe3c 100644 --- a/assets/images/product-illustrations/telescope.svg +++ b/assets/images/product-illustrations/telescope.svg @@ -1,79 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/signIn/google-logo.svg b/assets/images/signIn/google-logo.svg index 4fbdc804a0a2..169ea34b23ee 100644 --- a/assets/images/signIn/google-logo.svg +++ b/assets/images/signIn/google-logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__bigrocket.svg b/assets/images/simple-illustrations/simple-illustration__bigrocket.svg index 1afd5f66b6ea..64d6dc2200f0 100644 --- a/assets/images/simple-illustrations/simple-illustration__bigrocket.svg +++ b/assets/images/simple-illustrations/simple-illustration__bigrocket.svg @@ -1,100 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__commentbubbles.svg b/assets/images/simple-illustrations/simple-illustration__commentbubbles.svg index 829d3ee2e3fe..ab9d3ae4db70 100644 --- a/assets/images/simple-illustrations/simple-illustration__commentbubbles.svg +++ b/assets/images/simple-illustrations/simple-illustration__commentbubbles.svg @@ -1,22 +1 @@ - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__handcard.svg b/assets/images/simple-illustrations/simple-illustration__handcard.svg index 7419b33d425c..a49e0ee5b77f 100644 --- a/assets/images/simple-illustrations/simple-illustration__handcard.svg +++ b/assets/images/simple-illustrations/simple-illustration__handcard.svg @@ -1,41 +1 @@ - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__hotdogstand.svg b/assets/images/simple-illustrations/simple-illustration__hotdogstand.svg index 471b978bb97e..5b5e12a99a9b 100644 --- a/assets/images/simple-illustrations/simple-illustration__hotdogstand.svg +++ b/assets/images/simple-illustrations/simple-illustration__hotdogstand.svg @@ -1,98 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__hourglass.svg b/assets/images/simple-illustrations/simple-illustration__hourglass.svg index 539e1e45b795..683e74a657e8 100644 --- a/assets/images/simple-illustrations/simple-illustration__hourglass.svg +++ b/assets/images/simple-illustrations/simple-illustration__hourglass.svg @@ -1,56 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__mailbox.svg b/assets/images/simple-illustrations/simple-illustration__mailbox.svg index 81b1f508fb52..7af7c71e24f3 100644 --- a/assets/images/simple-illustrations/simple-illustration__mailbox.svg +++ b/assets/images/simple-illustrations/simple-illustration__mailbox.svg @@ -1,71 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__smallrocket.svg b/assets/images/simple-illustrations/simple-illustration__smallrocket.svg index 0f8f166c849f..388bb968a762 100644 --- a/assets/images/simple-illustrations/simple-illustration__smallrocket.svg +++ b/assets/images/simple-illustrations/simple-illustration__smallrocket.svg @@ -1,45 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/simple-illustrations/simple-illustration__trashcan.svg b/assets/images/simple-illustrations/simple-illustration__trashcan.svg index 4e66efa0a67e..66cc9ee27550 100644 --- a/assets/images/simple-illustrations/simple-illustration__trashcan.svg +++ b/assets/images/simple-illustrations/simple-illustration__trashcan.svg @@ -1,52 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/assets/images/thumbs-up.svg b/assets/images/thumbs-up.svg index ef81c88fc854..3e2a4a5125b6 100644 --- a/assets/images/thumbs-up.svg +++ b/assets/images/thumbs-up.svg @@ -1,8 +1 @@ - - - - - + \ No newline at end of file diff --git a/docs/assets/images/send-money.svg b/docs/assets/images/send-money.svg index e858f0d5c327..7abce818f09e 100644 --- a/docs/assets/images/send-money.svg +++ b/docs/assets/images/send-money.svg @@ -1,25 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/docs/assets/images/subscription-annual.svg b/docs/assets/images/subscription-annual.svg index a4b99a43b16e..f74ce086b2c7 100644 --- a/docs/assets/images/subscription-annual.svg +++ b/docs/assets/images/subscription-annual.svg @@ -1,23 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index b4056989a1c4..f361946c2584 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.25.0 + 1.4.25.5 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 4f75315fb1ec..bf9e98fec664 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -19,6 +19,6 @@ CFBundleSignature ???? CFBundleVersion - 1.4.25.0 + 1.4.25.5 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index a0328855047b..5ee62047829d 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -5,7 +5,7 @@ CFBundleShortVersionString 1.4.25 CFBundleVersion - 1.4.25.0 + 1.4.25.5 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 379194a70fd9..f433c4f1e1e2 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1180,7 +1180,7 @@ PODS: - React-Core - react-native-pager-view (6.2.2): - React-Core - - react-native-pdf (6.7.4): + - react-native-pdf (6.7.3): - React-Core - react-native-performance (5.1.0): - React-Core @@ -1911,7 +1911,7 @@ SPEC CHECKSUMS: react-native-key-command: 5af6ee30ff4932f78da6a2109017549042932aa5 react-native-netinfo: 8a7fd3f7130ef4ad2fb4276d5c9f8d3f28d2df3d react-native-pager-view: 02a5c4962530f7efc10dd51ee9cdabeff5e6c631 - react-native-pdf: 79aa75e39a80c1d45ffe58aa500f3cf08f267a2e + react-native-pdf: b4ca3d37a9a86d9165287741c8b2ef4d8940c00e react-native-performance: cef2b618d47b277fb5c3280b81a3aad1e72f2886 react-native-plaid-link-sdk: df1618a85a615d62ff34e34b76abb7a56497fbc1 react-native-quick-sqlite: bcc7a7a250a40222f18913a97cd356bf82d0a6c4 diff --git a/package-lock.json b/package-lock.json index 0acbc00bf99d..e9d4c4f90b2d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.4.25-0", + "version": "1.4.25-5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.25-0", + "version": "1.4.25-5", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -96,7 +96,7 @@ "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.126", "react-native-pager-view": "6.2.2", - "react-native-pdf": "^6.7.4", + "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.9.3", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#7a407cd4174d9838a944c1c2e1cb4a9737ac69c5", @@ -47079,9 +47079,9 @@ } }, "node_modules/react-native-pdf": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.4.tgz", - "integrity": "sha512-sBeNcsrTRnLjmiU9Wx7Uk0K2kPSQtKIIG+FECdrEG16TOdtmQ3iqqEwt0dmy0pJegpg07uES5BXqiKsKkRUIFw==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.3.tgz", + "integrity": "sha512-bK1fVkj18kBA5YlRFNJ3/vJ1bEX3FDHyAPY6ArtIdVs+vv0HzcK5WH9LSd2bxUsEMIyY9CSjP4j8BcxNXTiQkQ==", "dependencies": { "crypto-js": "4.2.0", "deprecated-react-native-prop-types": "^2.3.0" @@ -89718,9 +89718,9 @@ "requires": {} }, "react-native-pdf": { - "version": "6.7.4", - "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.4.tgz", - "integrity": "sha512-sBeNcsrTRnLjmiU9Wx7Uk0K2kPSQtKIIG+FECdrEG16TOdtmQ3iqqEwt0dmy0pJegpg07uES5BXqiKsKkRUIFw==", + "version": "6.7.3", + "resolved": "https://registry.npmjs.org/react-native-pdf/-/react-native-pdf-6.7.3.tgz", + "integrity": "sha512-bK1fVkj18kBA5YlRFNJ3/vJ1bEX3FDHyAPY6ArtIdVs+vv0HzcK5WH9LSd2bxUsEMIyY9CSjP4j8BcxNXTiQkQ==", "requires": { "crypto-js": "4.2.0", "deprecated-react-native-prop-types": "^2.3.0" diff --git a/package.json b/package.json index 8682d4ad7385..237d64e25b4a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.25-0", + "version": "1.4.25-5", "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.", @@ -144,7 +144,7 @@ "react-native-modal": "^13.0.0", "react-native-onyx": "1.0.126", "react-native-pager-view": "6.2.2", - "react-native-pdf": "^6.7.4", + "react-native-pdf": "6.7.3", "react-native-performance": "^5.1.0", "react-native-permissions": "^3.9.3", "react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#7a407cd4174d9838a944c1c2e1cb4a9737ac69c5", diff --git a/src/CONST.ts b/src/CONST.ts index f0f7ab736b78..d6f3d3cdcef6 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -639,18 +639,13 @@ const CONST = { ANNOUNCE: '#announce', ADMINS: '#admins', }, - STATE: { - OPEN: 'OPEN', - SUBMITTED: 'SUBMITTED', - PROCESSING: 'PROCESSING', - }, STATE_NUM: { OPEN: 0, - PROCESSING: 1, - SUBMITTED: 2, + SUBMITTED: 1, + APPROVED: 2, BILLING: 3, }, - STATUS: { + STATUS_NUM: { OPEN: 0, SUBMITTED: 1, CLOSED: 2, @@ -1449,6 +1444,8 @@ const CONST = { INVISIBLE_CHARACTERS_GROUPS: /[\p{C}\p{Z}]/gu, OTHER_INVISIBLE_CHARACTERS: /[\u3164]/g, + + REPORT_FIELD_TITLE: /{report:([a-zA-Z]+)}/g, }, PRONOUNS: { diff --git a/src/components/AvatarCropModal/ImageCropView.js b/src/components/AvatarCropModal/ImageCropView.js index 92cbe3a4da04..f69fe7eb5ecb 100644 --- a/src/components/AvatarCropModal/ImageCropView.js +++ b/src/components/AvatarCropModal/ImageCropView.js @@ -6,7 +6,6 @@ import Animated, {interpolate, useAnimatedStyle} from 'react-native-reanimated'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import useStyleUtils from '@hooks/useStyleUtils'; -import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import ControlSelection from '@libs/ControlSelection'; import gestureHandlerPropTypes from './gestureHandlerPropTypes'; @@ -51,7 +50,6 @@ const defaultProps = { }; function ImageCropView(props) { - const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const containerStyle = StyleUtils.getWidthAndHeightStyle(props.containerSize, props.containerSize); @@ -90,7 +88,8 @@ function ImageCropView(props) { diff --git a/src/components/BlockingViews/FullPageNotFoundView.tsx b/src/components/BlockingViews/FullPageNotFoundView.tsx index 5993e60861f5..807029addf5e 100644 --- a/src/components/BlockingViews/FullPageNotFoundView.tsx +++ b/src/components/BlockingViews/FullPageNotFoundView.tsx @@ -33,10 +33,10 @@ type FullPageNotFoundViewProps = { linkKey?: TranslationPaths; /** Method to trigger when pressing the back button of the header */ - onBackButtonPress: () => void; + onBackButtonPress?: () => void; /** Function to call when pressing the navigation link */ - onLinkPress: () => void; + onLinkPress?: () => void; }; // eslint-disable-next-line rulesdir/no-negated-variables diff --git a/src/components/LHNOptionsList/LHNOptionsList.js b/src/components/LHNOptionsList/LHNOptionsList.js index 71b14b6fadcd..6bb4973d0c64 100644 --- a/src/components/LHNOptionsList/LHNOptionsList.js +++ b/src/components/LHNOptionsList/LHNOptionsList.js @@ -118,7 +118,7 @@ function LHNOptionsList({ const transactionID = lodashGet(itemParentReportAction, ['originalMessage', 'IOUTransactionID'], ''); const itemTransaction = transactionID ? transactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`] : {}; const itemComment = draftComments[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`] || ''; - const participants = [...ReportUtils.getParticipantsIDs(itemFullReport), itemFullReport.ownerAccountID]; + const participants = [...ReportUtils.getParticipantsIDs(itemFullReport), itemFullReport.ownerAccountID, itemParentReportAction.actorAccountID]; const participantsPersonalDetails = OptionsListUtils.getPersonalDetailsForAccountIDs(participants, personalDetails); diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js index 197829bb1ea9..412aeedcf965 100755 --- a/src/components/OptionsSelector/BaseOptionsSelector.js +++ b/src/components/OptionsSelector/BaseOptionsSelector.js @@ -7,12 +7,9 @@ import ArrowKeyFocusManager from '@components/ArrowKeyFocusManager'; import Button from '@components/Button'; import FixedFooter from '@components/FixedFooter'; import FormHelpMessage from '@components/FormHelpMessage'; -import Icon from '@components/Icon'; -import {Info} from '@components/Icon/Expensicons'; import OptionsList from '@components/OptionsList'; -import {PressableWithoutFeedback} from '@components/Pressable'; +import ReferralProgramCTA from '@components/ReferralProgramCTA'; import ShowMoreButton from '@components/ShowMoreButton'; -import Text from '@components/Text'; import TextInput from '@components/TextInput'; import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import withNavigationFocus from '@components/withNavigationFocus'; @@ -21,10 +18,8 @@ import withThemeStyles, {withThemeStylesPropTypes} from '@components/withThemeSt import compose from '@libs/compose'; import getPlatform from '@libs/getPlatform'; import KeyboardShortcut from '@libs/KeyboardShortcut'; -import Navigation from '@libs/Navigation/Navigation'; import setSelection from '@libs/setSelection'; import CONST from '@src/CONST'; -import ROUTES from '@src/ROUTES'; import {defaultProps as optionsSelectorDefaultProps, propTypes as optionsSelectorPropTypes} from './optionsSelectorPropTypes'; const propTypes = { @@ -667,39 +662,7 @@ class BaseOptionsSelector extends Component { {this.props.shouldShowReferralCTA && ( - { - Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(this.props.referralContentType)); - }} - style={[ - this.props.themeStyles.p5, - this.props.themeStyles.w100, - this.props.themeStyles.br2, - this.props.themeStyles.highlightBG, - this.props.themeStyles.flexRow, - this.props.themeStyles.justifyContentBetween, - this.props.themeStyles.alignItemsCenter, - {gap: 10}, - ]} - accessibilityLabel="referral" - role={CONST.ACCESSIBILITY_ROLE.BUTTON} - > - - {this.props.translate(`referralProgram.${this.props.referralContentType}.buttonText1`)} - - {this.props.translate(`referralProgram.${this.props.referralContentType}.buttonText2`)} - - - - + )} diff --git a/src/pages/iou/MoneyRequestReferralProgramCTA.tsx b/src/components/ReferralProgramCTA.tsx similarity index 68% rename from src/pages/iou/MoneyRequestReferralProgramCTA.tsx rename to src/components/ReferralProgramCTA.tsx index 31394e1bd0e1..473d5cdbed08 100644 --- a/src/pages/iou/MoneyRequestReferralProgramCTA.tsx +++ b/src/components/ReferralProgramCTA.tsx @@ -1,20 +1,24 @@ import React from 'react'; -import Icon from '@components/Icon'; -import {Info} from '@components/Icon/Expensicons'; -import {PressableWithoutFeedback} from '@components/Pressable'; -import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; import Navigation from '@src/libs/Navigation/Navigation'; import ROUTES from '@src/ROUTES'; +import Icon from './Icon'; +import {Info} from './Icon/Expensicons'; +import {PressableWithoutFeedback} from './Pressable'; +import Text from './Text'; -type MoneyRequestReferralProgramCTAProps = { - referralContentType: typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST; +type ReferralProgramCTAProps = { + referralContentType: + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.MONEY_REQUEST + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.START_CHAT + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.SEND_MONEY + | typeof CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND; }; -function MoneyRequestReferralProgramCTA({referralContentType}: MoneyRequestReferralProgramCTAProps) { +function ReferralProgramCTA({referralContentType}: ReferralProgramCTAProps) { const {translate} = useLocalize(); const styles = useThemeStyles(); const theme = useTheme(); @@ -41,9 +45,10 @@ function MoneyRequestReferralProgramCTA({referralContentType}: MoneyRequestRefer src={Info} height={20} width={20} + fill={theme.icon} /> ); } -export default MoneyRequestReferralProgramCTA; +export default ReferralProgramCTA; diff --git a/src/components/ReportActionItem/MoneyReportView.tsx b/src/components/ReportActionItem/MoneyReportView.tsx index 16ea27b17f42..4fcca3e518a5 100644 --- a/src/components/ReportActionItem/MoneyReportView.tsx +++ b/src/components/ReportActionItem/MoneyReportView.tsx @@ -1,11 +1,14 @@ -import React from 'react'; +import React, {useMemo} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import {View} from 'react-native'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; +import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription'; +import OfflineWithFeedback from '@components/OfflineWithFeedback'; import SpacerView from '@components/SpacerView'; import Text from '@components/Text'; import useLocalize from '@hooks/useLocalize'; +import usePermissions from '@hooks/usePermissions'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -14,22 +17,26 @@ import * as CurrencyUtils from '@libs/CurrencyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground'; import variables from '@styles/variables'; -import type {Report} from '@src/types/onyx'; +import type {PolicyReportField, Report} from '@src/types/onyx'; type MoneyReportViewProps = { /** The report currently being looked at */ report: Report; + /** Policy report fields */ + policyReportFields: PolicyReportField[]; + /** Whether we should display the horizontal rule below the component */ shouldShowHorizontalRule: boolean; }; -function MoneyReportView({report, shouldShowHorizontalRule}: MoneyReportViewProps) { +function MoneyReportView({report, policyReportFields, shouldShowHorizontalRule}: MoneyReportViewProps) { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); const {translate} = useLocalize(); const {isSmallScreenWidth} = useWindowDimensions(); + const {canUseReportFields} = usePermissions(); const isSettled = ReportUtils.isSettled(report.reportID); const {totalDisplaySpend, nonReimbursableSpend, reimbursableSpend} = ReportUtils.getMoneyRequestSpendBreakdown(report); @@ -46,10 +53,41 @@ function MoneyReportView({report, shouldShowHorizontalRule}: MoneyReportViewProp StyleUtils.getColorStyle(theme.textSupporting), ]; + const sortedPolicyReportFields = useMemo( + () => policyReportFields.sort(({orderWeight: firstOrderWeight}, {orderWeight: secondOrderWeight}) => firstOrderWeight - secondOrderWeight), + [policyReportFields], + ); + return ( + {canUseReportFields && + sortedPolicyReportFields.map((reportField) => { + const title = ReportUtils.getReportFieldTitle(report, reportField); + return ( + + {}} + shouldShowRightIcon + disabled={false} + wrapperStyle={[styles.pv2, styles.taskDescriptionMenuItem]} + shouldGreyOutWhenDisabled={false} + numberOfLinesTitle={0} + interactive + shouldStackHorizontally={false} + onSecondaryInteraction={() => {}} + hoverAndPressStyle={false} + titleWithTooltips={[]} + /> + + ); + })} ({ + hasMissingSmartscanFields: ReportUtils.hasMissingSmartscanFields(props.iouReportID), + areAllRequestsBeingSmartScanned: ReportUtils.areAllRequestsBeingSmartScanned(props.iouReportID, props.action), + hasOnlyDistanceRequests: ReportUtils.hasOnlyDistanceRequestTransactions(props.iouReportID), + hasNonReimbursableTransactions: ReportUtils.hasNonReimbursableTransactions(props.iouReportID), + }), + // When transactions get updated these status may have changed, so that is a case where we also want to run this. + // eslint-disable-next-line react-hooks/exhaustive-deps + [props.transactions, props.iouReportID, props.action], + ); const managerID = props.iouReport.managerID || 0; const isCurrentUserManager = managerID === lodashGet(props.session, 'accountID'); @@ -162,7 +173,7 @@ function ReportPreview(props) { const previewSubtitle = formattedMerchant || props.translate('iou.requestCount', { - count: numberOfRequests, + count: numberOfRequests - numberOfScanningReceipts, scanningReceipts: numberOfScanningReceipts, }); @@ -218,28 +229,6 @@ function ReportPreview(props) { const bankAccountRoute = ReportUtils.getBankAccountRoute(props.chatReport); - useEffect(() => { - const unsubscribeOnyxTransaction = onyxSubscribe({ - key: ONYXKEYS.COLLECTION.TRANSACTION, - waitForCollectionCallback: true, - callback: (allTransactions) => { - if (_.isEmpty(allTransactions)) { - return; - } - - sethasMissingSmartscanFields(ReportUtils.hasMissingSmartscanFields(props.iouReportID)); - setAreAllRequestsBeingSmartScanned(ReportUtils.areAllRequestsBeingSmartScanned(props.iouReportID, props.action)); - setHasOnlyDistanceRequests(ReportUtils.hasOnlyDistanceRequestTransactions(props.iouReportID)); - setHasNonReimbursableTransactions(ReportUtils.hasNonReimbursableTransactions(props.iouReportID)); - }, - }); - - return () => { - unsubscribeOnyxTransaction(); - }; - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - const isPaidGroupPolicy = ReportUtils.isPaidGroupPolicyExpenseChat(props.chatReport); const isPolicyAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && lodashGet(props.policy, 'role') === CONST.POLICY.ROLE.ADMIN; const isPayer = isPaidGroupPolicy @@ -370,5 +359,8 @@ export default compose( session: { key: ONYXKEYS.SESSION, }, + transactions: { + key: ONYXKEYS.COLLECTION.TRANSACTION, + }, }), )(ReportPreview); diff --git a/src/components/ReportActionItem/TaskPreview.tsx b/src/components/ReportActionItem/TaskPreview.tsx index fbc58a381318..a509d8d922e1 100644 --- a/src/components/ReportActionItem/TaskPreview.tsx +++ b/src/components/ReportActionItem/TaskPreview.tsx @@ -84,12 +84,13 @@ function TaskPreview({ const StyleUtils = useStyleUtils(); const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT; const {translate} = useLocalize(); + // The reportAction might not contain details regarding the taskReport // Only the direct parent reportAction will contain details about the taskReport // Other linked reportActions will only contain the taskReportID and we will grab the details from there const isTaskCompleted = !isEmptyObject(taskReport) - ? taskReport?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && taskReport.statusNum === CONST.REPORT.STATUS.APPROVED - : action?.childStateNum === CONST.REPORT.STATE_NUM.SUBMITTED && action?.childStatusNum === CONST.REPORT.STATUS.APPROVED; + ? taskReport?.stateNum === CONST.REPORT.STATE_NUM.APPROVED && taskReport.statusNum === CONST.REPORT.STATUS_NUM.APPROVED + : action?.childStateNum === CONST.REPORT.STATE_NUM.APPROVED && action?.childStatusNum === CONST.REPORT.STATUS_NUM.APPROVED; const taskTitle = Str.htmlEncode(TaskUtils.getTaskTitle(taskReportID, action?.childReportName ?? '')); const taskAssigneeAccountID = Task.getTaskAssigneeAccountID(taskReport ?? {}) ?? action?.childManagerAccountID ?? ''; const assigneeLogin = personalDetails[taskAssigneeAccountID]?.login ?? ''; diff --git a/src/hooks/useDragAndDrop.ts b/src/hooks/useDragAndDrop.ts index 8c9054dc0bf1..7644d7bba5f0 100644 --- a/src/hooks/useDragAndDrop.ts +++ b/src/hooks/useDragAndDrop.ts @@ -1,6 +1,6 @@ import {useIsFocused} from '@react-navigation/native'; import type React from 'react'; -import {useCallback, useContext, useEffect, useState} from 'react'; +import {useCallback, useContext, useEffect, useRef, useState} from 'react'; import type {View} from 'react-native'; import {PopoverContext} from '@components/PopoverProvider'; @@ -31,6 +31,8 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow const [isDraggingOver, setIsDraggingOver] = useState(false); const {close: closePopover} = useContext(PopoverContext); + const enterTarget = useRef(null); + useEffect(() => { if (isFocused && !isDisabled) { return; @@ -76,6 +78,7 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow break; case DRAG_ENTER_EVENT: handleDragEvent(event); + enterTarget.current = event.target; if (isDraggingOver) { return; } @@ -86,7 +89,7 @@ export default function useDragAndDrop({dropZone, onDrop = () => {}, shouldAllow return; } // This is necessary because dragging over children will cause dragleave to execute on the parent. - if ((event.currentTarget as HTMLElement | null)?.contains(event.relatedTarget as HTMLElement | null)) { + if (enterTarget.current !== event.target) { return; } diff --git a/src/languages/en.ts b/src/languages/en.ts index 09fd295cb859..b6fa37560536 100755 --- a/src/languages/en.ts +++ b/src/languages/en.ts @@ -1,4 +1,5 @@ import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST'; +import Str from 'expensify-common/lib/str'; import CONST from '@src/CONST'; import type { AddressLineParams, @@ -588,7 +589,8 @@ export default { receiptStatusText: "Only you can see this receipt when it's scanning. Check back later or enter the details now.", receiptScanningFailed: 'Receipt scanning failed. Enter the details manually.', transactionPendingText: 'It takes a few days from the date the card was used for the transaction to post.', - requestCount: ({count, scanningReceipts = 0}: RequestCountParams) => `${count} requests${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}`, + requestCount: ({count, scanningReceipts = 0}: RequestCountParams) => + `${count} ${Str.pluralize('request', 'requests', count)}${scanningReceipts > 0 ? `, ${scanningReceipts} scanning` : ''}`, deleteRequest: 'Delete request', deleteConfirmation: 'Are you sure that you want to delete this request?', settledExpensify: 'Paid', diff --git a/src/languages/es.ts b/src/languages/es.ts index b977a614ae7e..271f0787bfde 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -1,3 +1,4 @@ +import Str from 'expensify-common/lib/str'; import CONST from '@src/CONST'; import type { AddressLineParams, @@ -581,7 +582,8 @@ export default { receiptStatusText: 'Solo tú puedes ver este recibo cuando se está escaneando. Vuelve más tarde o introduce los detalles ahora.', receiptScanningFailed: 'El escaneo de recibo ha fallado. Introduce los detalles manualmente.', transactionPendingText: 'La transacción tarda unos días en contabilizarse desde la fecha en que se utilizó la tarjeta.', - requestCount: ({count, scanningReceipts = 0}: RequestCountParams) => `${count} solicitudes${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}`, + requestCount: ({count, scanningReceipts = 0}: RequestCountParams) => + `${count} ${Str.pluralize('solicitude', 'solicitudes', count)}${scanningReceipts > 0 ? `, ${scanningReceipts} escaneando` : ''}`, deleteRequest: 'Eliminar pedido', deleteConfirmation: '¿Estás seguro de que quieres eliminar este pedido?', settledExpensify: 'Pagado', diff --git a/src/libs/E2E/apiMocks/openApp.ts b/src/libs/E2E/apiMocks/openApp.ts index ec714d693666..d6dd4a8f8003 100644 --- a/src/libs/E2E/apiMocks/openApp.ts +++ b/src/libs/E2E/apiMocks/openApp.ts @@ -2043,10 +2043,10 @@ const openApp = (): Response => ({ managerID: 16, currency: 'USD', chatReportID: '98817646', - state: 'SUBMITTED', cachedTotal: '($1,473.11)', total: 147311, stateNum: 1, + statusNum: 1, }, report_4249286573496381: { reportID: '4249286573496381', @@ -2054,10 +2054,10 @@ const openApp = (): Response => ({ managerID: 21, currency: 'USD', chatReportID: '4867098979334014', - state: 'SUBMITTED', cachedTotal: '($212.78)', total: 21278, stateNum: 1, + statusNum: 1, }, }, }, diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts index 8563db7db172..8d227fa6f697 100644 --- a/src/libs/Navigation/types.ts +++ b/src/libs/Navigation/types.ts @@ -3,6 +3,7 @@ import type {CommonActions, NavigationContainerRefWithCurrent, NavigationHelpers import type {ValueOf} from 'type-fest'; import type CONST from '@src/CONST'; import type NAVIGATORS from '@src/NAVIGATORS'; +import type {Route as Routes} from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; type NavigationRef = NavigationContainerRefWithCurrent; @@ -378,10 +379,11 @@ type RightModalNavigatorParamList = { type PublicScreensParamList = { [SCREENS.HOME]: undefined; [SCREENS.TRANSITION_BETWEEN_APPS]: { - shouldForceLogin: string; - email: string; - shortLivedAuthToken: string; - exitTo: string; + email?: string; + error?: string; + shortLivedAuthToken?: string; + shortLivedToken?: string; + exitTo?: Routes; }; [SCREENS.VALIDATE_LOGIN]: { accountID: string; diff --git a/src/libs/ReportUtils.ts b/src/libs/ReportUtils.ts index b632dbd1fd03..ba1e33360af1 100644 --- a/src/libs/ReportUtils.ts +++ b/src/libs/ReportUtils.ts @@ -14,7 +14,7 @@ import CONST from '@src/CONST'; import type {ParentNavigationSummaryParams, TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, Report, ReportAction, ReportMetadata, Session, Transaction} from '@src/types/onyx'; +import type {Beta, Login, PersonalDetails, PersonalDetailsList, Policy, PolicyReportField, Report, ReportAction, ReportMetadata, Session, Transaction} from '@src/types/onyx'; import type {Errors, Icon, PendingAction} from '@src/types/onyx/OnyxCommon'; import type {IOUMessage, OriginalMessageActionName, OriginalMessageCreated, ReimbursementDeQueuedMessage} from '@src/types/onyx/OriginalMessage'; import type {Status} from '@src/types/onyx/PersonalDetails'; @@ -112,7 +112,6 @@ type OptimisticExpenseReport = Pick< | 'ownerAccountID' | 'currency' | 'reportName' - | 'state' | 'stateNum' | 'statusNum' | 'total' @@ -311,13 +310,12 @@ type OptimisticIOUReport = Pick< | 'participantAccountIDs' | 'visibleChatMemberAccountIDs' | 'reportID' - | 'state' | 'stateNum' + | 'statusNum' | 'total' | 'reportName' | 'notificationPreference' | 'parentReportID' - | 'statusNum' | 'lastVisibleActionCreated' >; type DisplayNameWithTooltips = Array>; @@ -590,14 +588,16 @@ function isCanceledTaskReport(report: OnyxEntry | EmptyObject = {}, pare * @param parentReportAction - The parent report action of the report (Used to check if the task has been canceled) */ function isOpenTaskReport(report: OnyxEntry, parentReportAction: OnyxEntry | EmptyObject = {}): boolean { - return isTaskReport(report) && !isCanceledTaskReport(report, parentReportAction) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS.OPEN; + return ( + isTaskReport(report) && !isCanceledTaskReport(report, parentReportAction) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS_NUM.OPEN + ); } /** * Checks if a report is a completed task report. */ function isCompletedTaskReport(report: OnyxEntry): boolean { - return isTaskReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && report?.statusNum === CONST.REPORT.STATUS.APPROVED; + return isTaskReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.APPROVED && report?.statusNum === CONST.REPORT.STATUS_NUM.APPROVED; } /** @@ -612,14 +612,14 @@ function isReportManager(report: OnyxEntry): boolean { */ function isReportApproved(reportOrID: OnyxEntry | string | EmptyObject): boolean { const report = typeof reportOrID === 'string' ? allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${reportOrID}`] ?? null : reportOrID; - return report?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && report?.statusNum === CONST.REPORT.STATUS.APPROVED; + return report?.stateNum === CONST.REPORT.STATE_NUM.APPROVED && report?.statusNum === CONST.REPORT.STATUS_NUM.APPROVED; } /** * Checks if the supplied report is an expense report in Open state and status. */ function isDraftExpenseReport(report: OnyxEntry | EmptyObject): boolean { - return isExpenseReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS.OPEN; + return isExpenseReport(report) && report?.stateNum === CONST.REPORT.STATE_NUM.OPEN && report?.statusNum === CONST.REPORT.STATUS_NUM.OPEN; } /** @@ -650,11 +650,11 @@ function isSettled(reportID: string | undefined): boolean { // In case the payment is scheduled and we are waiting for the payee to set up their wallet, // consider the report as paid as well. - if (report.isWaitingOnBankAccount && report.statusNum === CONST.REPORT.STATUS.APPROVED) { + if (report.isWaitingOnBankAccount && report.statusNum === CONST.REPORT.STATUS_NUM.APPROVED) { return true; } - return report?.statusNum === CONST.REPORT.STATUS.REIMBURSED; + return report?.statusNum === CONST.REPORT.STATUS_NUM.REIMBURSED; } /** @@ -837,7 +837,7 @@ function isConciergeChatReport(report: OnyxEntry): boolean { * Returns true if report is still being processed */ function isProcessingReport(report: OnyxEntry | EmptyObject): boolean { - return report?.stateNum === CONST.REPORT.STATE_NUM.PROCESSING && report?.statusNum === CONST.REPORT.STATUS.SUBMITTED; + return report?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED && report?.statusNum === CONST.REPORT.STATUS_NUM.SUBMITTED; } /** @@ -943,7 +943,7 @@ function findLastAccessedReport( * Whether the provided report is an archived room */ function isArchivedRoom(report: OnyxEntry | EmptyObject): boolean { - return report?.statusNum === CONST.REPORT.STATUS.CLOSED && report?.stateNum === CONST.REPORT.STATE_NUM.SUBMITTED; + return report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED && report?.stateNum === CONST.REPORT.STATE_NUM.APPROVED; } /** @@ -1102,13 +1102,25 @@ function getReportNotificationPreference(report: OnyxEntry): string | nu } /** - * Returns whether or not the author of the action is this user - * + * Checks if the current user is the action's author */ -function isActionCreator(reportAction: OnyxEntry): boolean { +function isActionCreator(reportAction: OnyxEntry | Partial): boolean { return reportAction?.actorAccountID === currentUserAccountID; } +/** + * Returns the notification preference of the action's child report if it exists. + * Otherwise, calculates it based on the action's authorship. + */ +function getChildReportNotificationPreference(reportAction: OnyxEntry | Partial): NotificationPreference { + const childReportNotificationPreference = reportAction?.childReportNotificationPreference ?? ''; + if (childReportNotificationPreference) { + return childReportNotificationPreference; + } + + return isActionCreator(reportAction) ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; +} + /** * Can only delete if the author is this user and the action is an ADDCOMMENT action or an IOU action in an unsettled report, or if the user is a * policy admin @@ -2531,7 +2543,7 @@ function buildOptimisticTaskCommentReportAction(taskReportID: string, taskTitle: reportAction.reportAction.childType = CONST.REPORT.TYPE.TASK; reportAction.reportAction.childReportName = taskTitle; reportAction.reportAction.childManagerAccountID = taskAssigneeAccountID; - reportAction.reportAction.childStatusNum = CONST.REPORT.STATUS.OPEN; + reportAction.reportAction.childStatusNum = CONST.REPORT.STATUS_NUM.OPEN; reportAction.reportAction.childStateNum = CONST.REPORT.STATE_NUM.OPEN; return reportAction; @@ -2566,9 +2578,8 @@ function buildOptimisticIOUReport(payeeAccountID: number, payerAccountID: number participantAccountIDs: participantsAccountIDs, visibleChatMemberAccountIDs: participantsAccountIDs, reportID: generateReportID(), - state: CONST.REPORT.STATE.SUBMITTED, - stateNum: isSendingMoney ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: isSendingMoney ? CONST.REPORT.STATUS.REIMBURSED : CONST.REPORT.STATE_NUM.PROCESSING, + stateNum: isSendingMoney ? CONST.REPORT.STATE_NUM.APPROVED : CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: isSendingMoney ? CONST.REPORT.STATUS_NUM.REIMBURSED : CONST.REPORT.STATE_NUM.SUBMITTED, total, // We don't translate reportName because the server response is always in English @@ -2599,9 +2610,8 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa const isFree = policy?.type === CONST.POLICY.TYPE.FREE; // Define the state and status of the report based on whether the policy is free or paid - const state = isFree ? CONST.REPORT.STATE.SUBMITTED : CONST.REPORT.STATE.OPEN; - const stateNum = isFree ? CONST.REPORT.STATE_NUM.PROCESSING : CONST.REPORT.STATE_NUM.OPEN; - const statusNum = isFree ? CONST.REPORT.STATUS.SUBMITTED : CONST.REPORT.STATUS.OPEN; + const stateNum = isFree ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.OPEN; + const statusNum = isFree ? CONST.REPORT.STATUS_NUM.SUBMITTED : CONST.REPORT.STATUS_NUM.OPEN; return { reportID: generateReportID(), @@ -2613,7 +2623,6 @@ function buildOptimisticExpenseReport(chatReportID: string, policyID: string, pa // We don't translate reportName because the server response is always in English reportName: `${policyName} owes ${formattedTotal}`, - state, stateNum, statusNum, total: storedTotal, @@ -3353,7 +3362,7 @@ function buildOptimisticTaskReport( parentReportID, policyID, stateNum: CONST.REPORT.STATE_NUM.OPEN, - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, lastVisibleActionCreated: DateUtils.getDBTime(), }; @@ -3590,7 +3599,7 @@ function getChatByParticipantsAndPolicy(newParticipantList: number[], policyID: if (!report?.participantAccountIDs) { return false; } - const sortedParticipanctsAccountIDs = report.parentReportActionIDs?.sort(); + const sortedParticipanctsAccountIDs = report.participantAccountIDs?.sort(); // Only return the room if it has all the participants and is not a policy room return report.policyID === policyID && lodashIsEqual(newParticipantList, sortedParticipanctsAccountIDs); }) ?? null @@ -4375,6 +4384,25 @@ function navigateToPrivateNotes(report: Report, session: Session) { Navigation.navigate(ROUTES.PRIVATE_NOTES_LIST.getRoute(report.reportID)); } +/** + * Given a report field and a report, get the title of the field. + * This is specially useful when we have a report field of type formula. + */ +function getReportFieldTitle(report: OnyxEntry, reportField: PolicyReportField): string { + const value = report?.reportFields?.[reportField.fieldID] ?? reportField.defaultValue; + + if (reportField.type !== 'formula') { + return value; + } + + return value.replaceAll(CONST.REGEX.REPORT_FIELD_TITLE, (match, property) => { + if (report && property in report) { + return report[property as keyof Report]?.toString() ?? match; + } + return match; + }); +} + /** * Checks if thread replies should be displayed */ @@ -4583,8 +4611,10 @@ export { canEditWriteCapability, hasSmartscanError, shouldAutoFocusOnKeyPress, + getReportFieldTitle, shouldDisplayThreadReplies, shouldDisableThread, + getChildReportNotificationPreference, }; export type {ExpenseOriginalMessage, OptionData, OptimisticChatReport, OptimisticCreatedReportAction}; diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index ca572452cc82..49b6a3b445e1 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -945,6 +945,7 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t const transaction = allTransactions[`${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`]; const iouReport = allReports[`${ONYXKEYS.COLLECTION.REPORT}${transactionThread.parentReportID}`]; const isFromExpenseReport = ReportUtils.isExpenseReport(iouReport); + const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction); const updatedTransaction = TransactionUtils.getUpdatedTransaction(transaction, transactionChanges, isFromExpenseReport); const transactionDetails = ReportUtils.getTransactionDetails(updatedTransaction); @@ -1030,6 +1031,30 @@ function getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, t }, }); + if (isScanning && (_.has(transactionChanges, 'amount') || _.has(transactionChanges, 'currency'))) { + optimisticData.push( + ...[ + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`, + value: { + [transactionThread.parentReportActionID]: { + whisperedToAccountIDs: [], + }, + }, + }, + { + onyxMethod: Onyx.METHOD.MERGE, + key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`, + value: { + [iouReport.parentReportActionID]: { + whisperedToAccountIDs: [], + }, + }, + }, + ], + ); + } // Update recently used categories if the category is changed if (_.has(transactionChanges, 'category')) { const optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, transactionChanges.category); @@ -1158,6 +1183,21 @@ function updateMoneyRequestTag(transactionID, transactionThreadReportID, tag) { API.write('UpdateMoneyRequestTag', params, onyxData); } +/** + * Updates the description of a money request + * + * @param {String} transactionID + * @param {Number} transactionThreadReportID + * @param {String} comment + */ +function updateMoneyRequestDescription(transactionID, transactionThreadReportID, comment) { + const transactionChanges = { + comment, + }; + const {params, onyxData} = getUpdateMoneyRequestParams(transactionID, transactionThreadReportID, transactionChanges, true); + API.write('UpdateMoneyRequestDescription', params, onyxData); +} + /** * Edits an existing distance request * @@ -3016,7 +3056,7 @@ function getPayMoneyRequestParams(chatReport, iouReport, recipient, paymentMetho lastMessageText: optimisticIOUReportAction.message[0].text, lastMessageHtml: optimisticIOUReportAction.message[0].html, hasOutstandingChildRequest: false, - statusNum: CONST.REPORT.STATUS.REIMBURSED, + statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, }, }, { @@ -3164,8 +3204,8 @@ function approveMoneyRequest(expenseReport) { ...expenseReport, lastMessageText: optimisticApprovedReportAction.message[0].text, lastMessageHtml: optimisticApprovedReportAction.message[0].html, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - statusNum: CONST.REPORT.STATUS.APPROVED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, }, }; const optimisticData = [optimisticIOUReportData, optimisticReportActionsData]; @@ -3238,9 +3278,8 @@ function submitReport(expenseReport) { ...expenseReport, lastMessageText: lodashGet(optimisticSubmittedReportAction, 'message.0.text', ''), lastMessageHtml: lodashGet(optimisticSubmittedReportAction, 'message.0.html', ''), - state: CONST.REPORT.STATE.SUBMITTED, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }, }, ...(parentReport.reportID @@ -3286,7 +3325,7 @@ function submitReport(expenseReport) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, stateNum: CONST.REPORT.STATE_NUM.OPEN, }, }, @@ -3354,9 +3393,8 @@ function cancelPayment(expenseReport, chatReport) { ...expenseReport, lastMessageText: lodashGet(optimisticReportAction, 'message.0.text', ''), lastMessageHtml: lodashGet(optimisticReportAction, 'message.0.html', ''), - state: isFree ? CONST.REPORT.STATE.SUBMITTED : CONST.REPORT.STATE.OPEN, - stateNum: isFree ? CONST.REPORT.STATE_NUM.PROCESSING : CONST.REPORT.STATE.OPEN, - statusNum: isFree ? CONST.REPORT.STATUS.SUBMITTED : CONST.REPORT.STATE.OPEN, + stateNum: isFree ? CONST.REPORT.STATE_NUM.SUBMITTED : CONST.REPORT.STATE_NUM.OPEN, + statusNum: isFree ? CONST.REPORT.STATUS_NUM.SUBMITTED : CONST.REPORT.STATUS_NUM.OPEN, }, }, ...(chatReport.reportID @@ -3401,7 +3439,7 @@ function cancelPayment(expenseReport, chatReport) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`, value: { - statusNum: CONST.REPORT.STATUS.REIMBURSED, + statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, }, }, ...(chatReport.reportID @@ -3756,6 +3794,7 @@ export { updateMoneyRequestMerchant, updateMoneyRequestTag, updateMoneyRequestAmountAndCurrency, + updateMoneyRequestDescription, replaceReceipt, detachReceipt, getIOUReportID, diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index a21b795fa89a..25c8cf5ade80 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -173,8 +173,8 @@ function deleteWorkspace(policyID, reports, policyName) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, value: { - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - statusNum: CONST.REPORT.STATUS.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, hasDraft: false, oldPolicyName: allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`].name, }, @@ -368,8 +368,8 @@ function removeMembers(accountIDs, policyID) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`, value: { - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, oldPolicyName: policy.name, hasDraft: false, }, @@ -475,7 +475,7 @@ function createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs, hasOutsta key: `${ONYXKEYS.COLLECTION.REPORT}${oldChat.reportID}`, value: { stateNum: CONST.REPORT.STATE_NUM.OPEN, - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, }, }); return; diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts index b182b7019846..9067e5592937 100644 --- a/src/libs/actions/Report.ts +++ b/src/libs/actions/Report.ts @@ -741,7 +741,7 @@ function navigateToAndOpenChildReport(childReportID = '0', parentReportAction: P '', undefined, undefined, - CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, + ReportUtils.getChildReportNotificationPreference(parentReportAction), parentReportAction.reportActionID, parentReportID, ); @@ -2095,8 +2095,8 @@ function leaveRoom(reportID: string, isWorkspaceMemberLeavingWorkspaceRoom = fal } : { reportID: null, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - statusNum: CONST.REPORT.STATUS.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, notificationPreference: CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, }, }, diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js index e46c9fc380cd..a135c2c8fa94 100644 --- a/src/libs/actions/Task.js +++ b/src/libs/actions/Task.js @@ -246,8 +246,8 @@ function completeTask(taskReport) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`, value: { - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - statusNum: CONST.REPORT.STATUS.APPROVED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, }, }, @@ -275,7 +275,7 @@ function completeTask(taskReport) { key: `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`, value: { stateNum: CONST.REPORT.STATE_NUM.OPEN, - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, }, }, { @@ -314,7 +314,7 @@ function reopenTask(taskReport) { key: `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`, value: { stateNum: CONST.REPORT.STATE_NUM.OPEN, - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, lastVisibleActionCreated: reopenedTaskReportAction.created, lastMessageText: message, lastActorAccountID: reopenedTaskReportAction.actorAccountID, @@ -344,8 +344,8 @@ function reopenTask(taskReport) { onyxMethod: Onyx.METHOD.MERGE, key: `${ONYXKEYS.COLLECTION.REPORT}${taskReportID}`, value: { - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - statusNum: CONST.REPORT.STATUS.APPROVED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, }, }, { diff --git a/src/libs/actions/Welcome.ts b/src/libs/actions/Welcome.ts index 5046449c7389..3e3cba49480d 100644 --- a/src/libs/actions/Welcome.ts +++ b/src/libs/actions/Welcome.ts @@ -132,7 +132,7 @@ function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => false} const workspaceChatReport = Object.values(allReports ?? {}).find((report) => { if (report) { - return ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS.CLOSED; + return ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS_NUM.CLOSED; } return false; }); diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js index fe43d96001a0..606d3da1ddb9 100644 --- a/src/pages/EditRequestPage.js +++ b/src/pages/EditRequestPage.js @@ -176,18 +176,22 @@ function EditRequestPage({report, route, policyCategories, policyTags, parentRep [transactionTag, transaction.transactionID, report.reportID], ); + const saveComment = useCallback( + ({comment: newComment}) => { + // Only update comment if it has changed + if (newComment.trim() !== transactionDescription) { + IOU.updateMoneyRequestDescription(transaction.transactionID, report.reportID, newComment.trim()); + } + Navigation.dismissModal(); + }, + [transactionDescription, transaction.transactionID, report.reportID], + ); + if (fieldToEdit === CONST.EDIT_REQUEST_FIELD.DESCRIPTION) { return ( { - // In case the comment hasn't been changed, do not make the API request. - if (transactionChanges.comment.trim() === transactionDescription) { - Navigation.dismissModal(); - return; - } - editMoneyRequest({comment: transactionChanges.comment.trim()}); - }} + onSubmit={saveComment} /> ); } diff --git a/src/pages/ErrorPage/ErrorBodyText/index.js b/src/pages/ErrorPage/ErrorBodyText/index.tsx similarity index 54% rename from src/pages/ErrorPage/ErrorBodyText/index.js rename to src/pages/ErrorPage/ErrorBodyText/index.tsx index 47b765f8f5e8..e675e0447361 100644 --- a/src/pages/ErrorPage/ErrorBodyText/index.js +++ b/src/pages/ErrorPage/ErrorBodyText/index.tsx @@ -1,29 +1,27 @@ import React from 'react'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useLocalize from '@hooks/useLocalize'; import useThemeStyles from '@hooks/useThemeStyles'; import CONST from '@src/CONST'; -const propTypes = { - ...withLocalizePropTypes, -}; - -function ErrorBodyText(props) { +function ErrorBodyText() { const styles = useThemeStyles(); + const {translate} = useLocalize(); + return ( - {`${props.translate('genericErrorPage.body.helpTextMobile')} `} + {`${translate('genericErrorPage.body.helpTextMobile')} `} - {props.translate('genericErrorPage.body.helpTextWeb')} + {translate('genericErrorPage.body.helpTextWeb')} ); } ErrorBodyText.displayName = 'ErrorBodyText'; -ErrorBodyText.propTypes = propTypes; -export default withLocalize(ErrorBodyText); + +export default ErrorBodyText; diff --git a/src/pages/ErrorPage/ErrorBodyText/index.website.js b/src/pages/ErrorPage/ErrorBodyText/index.website.tsx similarity index 100% rename from src/pages/ErrorPage/ErrorBodyText/index.website.js rename to src/pages/ErrorPage/ErrorBodyText/index.website.tsx diff --git a/src/pages/ErrorPage/GenericErrorPage.js b/src/pages/ErrorPage/GenericErrorPage.tsx similarity index 91% rename from src/pages/ErrorPage/GenericErrorPage.js rename to src/pages/ErrorPage/GenericErrorPage.tsx index 56fb5b970084..f4f1d91418c7 100644 --- a/src/pages/ErrorPage/GenericErrorPage.js +++ b/src/pages/ErrorPage/GenericErrorPage.tsx @@ -9,7 +9,7 @@ import ImageSVG from '@components/ImageSVG'; import SafeAreaConsumer from '@components/SafeAreaConsumer'; import Text from '@components/Text'; import TextLink from '@components/TextLink'; -import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; +import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -18,20 +18,18 @@ import * as Session from '@userActions/Session'; import CONST from '@src/CONST'; import ErrorBodyText from './ErrorBodyText'; -const propTypes = { - ...withLocalizePropTypes, -}; - -function GenericErrorPage({translate}) { +function GenericErrorPage() { const theme = useTheme(); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); + const {translate} = useLocalize(); + const {resetBoundary} = useErrorBoundary(); return ( {({paddingBottom}) => ( - + @@ -78,7 +76,7 @@ function GenericErrorPage({translate}) { - + void; }; // eslint-disable-next-line rulesdir/no-negated-variables -function NotFoundPage(props) { +function NotFoundPage({onBackButtonPress}: NotFoundPageProps) { return ( ); } NotFoundPage.displayName = 'NotFoundPage'; -NotFoundPage.propTypes = propTypes; -NotFoundPage.defaultProps = defaultProps; export default NotFoundPage; diff --git a/src/pages/LogInWithShortLivedAuthTokenPage.js b/src/pages/LogInWithShortLivedAuthTokenPage.tsx similarity index 65% rename from src/pages/LogInWithShortLivedAuthTokenPage.js rename to src/pages/LogInWithShortLivedAuthTokenPage.tsx index 1fe9b67eef16..c5f8a9c20d5b 100644 --- a/src/pages/LogInWithShortLivedAuthTokenPage.js +++ b/src/pages/LogInWithShortLivedAuthTokenPage.tsx @@ -1,7 +1,7 @@ -import lodashGet from 'lodash/get'; -import PropTypes from 'prop-types'; +import type {StackScreenProps} from '@react-navigation/stack'; import React, {useEffect} from 'react'; import {View} from 'react-native'; +import type {OnyxEntry} from 'react-native-onyx'; import {withOnyx} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Icon from '@components/Icon'; @@ -13,62 +13,40 @@ import useLocalize from '@hooks/useLocalize'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import Navigation from '@libs/Navigation/Navigation'; +import type {PublicScreensParamList} from '@libs/Navigation/types'; import * as Session from '@userActions/Session'; import ONYXKEYS from '@src/ONYXKEYS'; +import type SCREENS from '@src/SCREENS'; +import type {Account} from '@src/types/onyx'; -const propTypes = { - /** The parameters needed to authenticate with a short-lived token are in the URL */ - route: PropTypes.shape({ - /** Each parameter passed via the URL */ - params: PropTypes.shape({ - /** Short-lived authToken to sign in a user */ - shortLivedAuthToken: PropTypes.string, - - /** Short-lived authToken to sign in as a user, if they are coming from the old mobile app */ - shortLivedToken: PropTypes.string, - - /** The email of the transitioning user */ - email: PropTypes.string, - }), - }).isRequired, - +type LogInWithShortLivedAuthTokenPageOnyxProps = { /** The details about the account that the user is signing in with */ - account: PropTypes.shape({ - /** Whether a sign is loading */ - isLoading: PropTypes.bool, - }), + account: OnyxEntry; }; -const defaultProps = { - account: { - isLoading: false, - }, -}; +type LogInWithShortLivedAuthTokenPageProps = LogInWithShortLivedAuthTokenPageOnyxProps & StackScreenProps; -function LogInWithShortLivedAuthTokenPage(props) { +function LogInWithShortLivedAuthTokenPage({route, account}: LogInWithShortLivedAuthTokenPageProps) { const theme = useTheme(); const styles = useThemeStyles(); const {translate} = useLocalize(); + const {email = '', shortLivedAuthToken = '', shortLivedToken = '', exitTo, error} = route?.params ?? {}; useEffect(() => { - const email = lodashGet(props, 'route.params.email', ''); - // We have to check for both shortLivedAuthToken and shortLivedToken, as the old mobile app uses shortLivedToken, and is not being actively updated. - const shortLivedAuthToken = lodashGet(props, 'route.params.shortLivedAuthToken', '') || lodashGet(props, 'route.params.shortLivedToken', ''); + const token = shortLivedAuthToken || shortLivedToken; // Try to authenticate using the shortLivedToken if we're not already trying to load the accounts - if (shortLivedAuthToken && !props.account.isLoading) { - Session.signInWithShortLivedAuthToken(email, shortLivedAuthToken); + if (token && !account?.isLoading) { + Session.signInWithShortLivedAuthToken(email, token); return; } // If an error is returned as part of the route, ensure we set it in the onyxData for the account - const error = lodashGet(props, 'route.params.error', ''); if (error) { Session.setAccountError(error); } - const exitTo = lodashGet(props, 'route.params.exitTo', ''); if (exitTo) { Navigation.isNavigationReady().then(() => { Navigation.navigate(exitTo); @@ -76,9 +54,9 @@ function LogInWithShortLivedAuthTokenPage(props) { } // The only dependencies of the effect are based on props.route // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.route]); + }, [route]); - if (props.account.isLoading) { + if (account?.isLoading) { return ; } @@ -94,7 +72,7 @@ function LogInWithShortLivedAuthTokenPage(props) { {translate('deeplinkWrapper.launching')} - + {translate('deeplinkWrapper.expired')}{' '} { @@ -119,10 +97,8 @@ function LogInWithShortLivedAuthTokenPage(props) { ); } -LogInWithShortLivedAuthTokenPage.propTypes = propTypes; -LogInWithShortLivedAuthTokenPage.defaultProps = defaultProps; LogInWithShortLivedAuthTokenPage.displayName = 'LogInWithShortLivedAuthTokenPage'; -export default withOnyx({ +export default withOnyx({ account: {key: ONYXKEYS.ACCOUNT}, })(LogInWithShortLivedAuthTokenPage); diff --git a/src/pages/SearchPage/SearchPageFooter.tsx b/src/pages/SearchPage/SearchPageFooter.tsx index 69429962869b..e0ef67ad9ec3 100644 --- a/src/pages/SearchPage/SearchPageFooter.tsx +++ b/src/pages/SearchPage/SearchPageFooter.tsx @@ -1,55 +1,15 @@ import React from 'react'; import {View} from 'react-native'; -import Icon from '@components/Icon'; -import {Info} from '@components/Icon/Expensicons'; -import {PressableWithoutFeedback} from '@components/Pressable'; -import Text from '@components/Text'; -import useLocalize from '@hooks/useLocalize'; -import useTheme from '@hooks/useTheme'; +import ReferralProgramCTA from '@components/ReferralProgramCTA'; import useThemeStyles from '@hooks/useThemeStyles'; -import Navigation from '@libs/Navigation/Navigation'; import CONST from '@src/CONST'; -import ROUTES from '@src/ROUTES'; function SearchPageFooter() { const themeStyles = useThemeStyles(); - const theme = useTheme(); - const {translate} = useLocalize(); return ( - { - Navigation.navigate(ROUTES.REFERRAL_DETAILS_MODAL.getRoute(CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND)); - }} - style={[ - themeStyles.p5, - themeStyles.w100, - themeStyles.br2, - themeStyles.highlightBG, - themeStyles.flexRow, - themeStyles.justifyContentBetween, - themeStyles.alignItemsCenter, - {gap: 10}, - ]} - accessibilityLabel="referral" - role={CONST.ACCESSIBILITY_ROLE.BUTTON} - > - - {translate(`referralProgram.${CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND}.buttonText1`)} - - {translate(`referralProgram.${CONST.REFERRAL_PROGRAM.CONTENT_TYPES.REFER_FRIEND}.buttonText2`)} - - - - + ); } diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js index edf6b65b2f4a..9b2765718250 100644 --- a/src/pages/home/HeaderView.js +++ b/src/pages/home/HeaderView.js @@ -109,9 +109,7 @@ function HeaderView(props) { const isAutomatedExpensifyAccount = ReportUtils.hasSingleParticipant(props.report) && ReportUtils.hasAutomatedExpensifyAccountIDs(participants); const parentReportAction = ReportActionsUtils.getParentReportAction(props.report); const isCanceledTaskReport = ReportUtils.isCanceledTaskReport(props.report, parentReportAction); - const lastVisibleMessage = ReportActionsUtils.getLastVisibleMessage(props.report.reportID); const isWhisperAction = ReportActionsUtils.isWhisperAction(parentReportAction); - const isEmptyChat = !props.report.lastMessageText && !props.report.lastMessageTranslationKey && !lastVisibleMessage.lastMessageText && !lastVisibleMessage.lastMessageTranslationKey; const isUserCreatedPolicyRoom = ReportUtils.isUserCreatedPolicyRoom(props.report); const isPolicyMember = useMemo(() => !_.isEmpty(props.policy), [props.policy]); const canLeaveRoom = ReportUtils.canLeaveRoom(props.report, isPolicyMember); @@ -133,7 +131,7 @@ function HeaderView(props) { } // Task is not closed - if (props.report.stateNum !== CONST.REPORT.STATE_NUM.SUBMITTED && props.report.statusNum !== CONST.REPORT.STATUS.CLOSED && canModifyTask) { + if (props.report.stateNum !== CONST.REPORT.STATE_NUM.APPROVED && props.report.statusNum !== CONST.REPORT.STATUS_NUM.CLOSED && canModifyTask) { threeDotMenuItems.push({ icon: Expensicons.Trashcan, text: translate('common.delete'), @@ -153,7 +151,7 @@ function HeaderView(props) { ), ); - const canJoinOrLeave = (isChatThread && !isEmptyChat) || isUserCreatedPolicyRoom || canLeaveRoom; + const canJoinOrLeave = isChatThread || isUserCreatedPolicyRoom || canLeaveRoom; const canJoin = canJoinOrLeave && !isWhisperAction && props.report.notificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const canLeave = canJoinOrLeave && ((isChatThread && props.report.notificationPreference.length) || isUserCreatedPolicyRoom || canLeaveRoom); if (canJoin) { diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js index 64e48ecd5509..b35d9240f3f7 100644 --- a/src/pages/home/ReportScreen.js +++ b/src/pages/home/ReportScreen.js @@ -187,7 +187,7 @@ function ReportScreen({ // There are no reportActions at all to display and we are still in the process of loading the next set of actions. const isLoadingInitialReportActions = _.isEmpty(reportActions) && reportMetadata.isLoadingInitialReportActions; - const isOptimisticDelete = lodashGet(report, 'statusNum') === CONST.REPORT.STATUS.CLOSED; + const isOptimisticDelete = lodashGet(report, 'statusNum') === CONST.REPORT.STATUS_NUM.CLOSED; const shouldHideReport = !ReportUtils.canAccessReport(report, policies, betas); const isLoading = !reportID || !isSidebarLoaded || _.isEmpty(personalDetails); const isSingleTransactionView = ReportUtils.isMoneyRequest(report); @@ -383,8 +383,8 @@ function ReportScreen({ (prevOnyxReportID && prevOnyxReportID === routeReportID && !onyxReportID && - prevReport.statusNum === CONST.REPORT.STATUS.OPEN && - (report.statusNum === CONST.REPORT.STATUS.CLOSED || (!report.statusNum && !prevReport.parentReportID && prevReport.chatType === CONST.REPORT.CHAT_TYPE.POLICY_ROOM))) || + prevReport.statusNum === CONST.REPORT.STATUS_NUM.OPEN && + (report.statusNum === CONST.REPORT.STATUS_NUM.CLOSED || (!report.statusNum && !prevReport.parentReportID && prevReport.chatType === CONST.REPORT.CHAT_TYPE.POLICY_ROOM))) || ((ReportUtils.isMoneyRequest(prevReport) || ReportUtils.isMoneyRequestReport(prevReport)) && _.isEmpty(report)) ) { Navigation.dismissModal(); diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js index 7db39c1ed856..aa815b0b32dc 100644 --- a/src/pages/home/report/ContextMenu/ContextMenuActions.js +++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js @@ -156,14 +156,10 @@ export default [ successTextTranslateKey: '', successIcon: null, shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID) => { - let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', ''); - if (!childReportNotificationPreference) { - const isActionCreator = ReportUtils.isActionCreator(reportAction); - childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; - } + const childReportNotificationPreference = ReportUtils.getChildReportNotificationPreference(reportAction); const isDeletedAction = ReportActionsUtils.isDeletedAction(reportAction); const shouldDisplayThreadReplies = ReportUtils.shouldDisplayThreadReplies(reportAction, reportID); - const subscribed = childReportNotificationPreference !== 'hidden'; + const subscribed = childReportNotificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; const isCommentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && !ReportUtils.isThreadFirstChat(reportAction, reportID); const isReportPreviewAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW; const isIOUAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !ReportActionsUtils.isSplitBillAction(reportAction); @@ -171,11 +167,7 @@ export default [ return !subscribed && !isWhisperAction && (isCommentAction || isReportPreviewAction || isIOUAction) && (!isDeletedAction || shouldDisplayThreadReplies); }, onPress: (closePopover, {reportAction, reportID}) => { - let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', ''); - if (!childReportNotificationPreference) { - const isActionCreator = ReportUtils.isActionCreator(reportAction); - childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; - } + const childReportNotificationPreference = ReportUtils.getChildReportNotificationPreference(reportAction); if (closePopover) { hideContextMenu(false, () => { ReportActionComposeFocusManager.focus(); @@ -196,14 +188,10 @@ export default [ successTextTranslateKey: '', successIcon: null, shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID) => { - let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', ''); - if (!childReportNotificationPreference) { - const isActionCreator = ReportUtils.isActionCreator(reportAction); - childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; - } + const childReportNotificationPreference = ReportUtils.getChildReportNotificationPreference(reportAction); const isDeletedAction = ReportActionsUtils.isDeletedAction(reportAction); const shouldDisplayThreadReplies = ReportUtils.shouldDisplayThreadReplies(reportAction, reportID); - const subscribed = childReportNotificationPreference !== 'hidden'; + const subscribed = childReportNotificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; if (type !== CONST.CONTEXT_MENU_TYPES.REPORT_ACTION) { return false; } @@ -213,11 +201,7 @@ export default [ return subscribed && (isCommentAction || isReportPreviewAction || isIOUAction) && (!isDeletedAction || shouldDisplayThreadReplies); }, onPress: (closePopover, {reportAction, reportID}) => { - let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', ''); - if (!childReportNotificationPreference) { - const isActionCreator = ReportUtils.isActionCreator(reportAction); - childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN; - } + const childReportNotificationPreference = ReportUtils.getChildReportNotificationPreference(reportAction); if (closePopover) { hideContextMenu(false, () => { ReportActionComposeFocusManager.focus(); diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js index 6c1d71625dc9..413807b1f992 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/ComposerWithSuggestions.js @@ -127,8 +127,8 @@ function ComposerWithSuggestions({ const maxComposerLines = isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES; const isEmptyChat = useMemo(() => _.size(reportActions) === 1, [reportActions]); - const parentAction = ReportActionsUtils.getParentReportAction(report); - const shouldAutoFocus = !modal.isVisible && (shouldFocusInputOnScreenFocus || (isEmptyChat && !ReportActionsUtils.isTransactionThread(parentAction))) && shouldShowComposeInput; + const parentReportAction = lodashGet(parentReportActions, [report.parentReportActionID]); + const shouldAutoFocus = !modal.isVisible && (shouldFocusInputOnScreenFocus || (isEmptyChat && !ReportActionsUtils.isTransactionThread(parentReportAction))) && shouldShowComposeInput; const valueRef = useRef(value); valueRef.current = value; @@ -344,9 +344,6 @@ function ComposerWithSuggestions({ const valueLength = valueRef.current.length; if (e.key === CONST.KEYBOARD_SHORTCUTS.ARROW_UP.shortcutKey && textInputRef.current.selectionStart === 0 && valueLength === 0 && !ReportUtils.chatIncludesChronos(report)) { e.preventDefault(); - - const parentReportActionID = lodashGet(report, 'parentReportActionID', ''); - const parentReportAction = lodashGet(parentReportActions, [parentReportActionID], {}); const lastReportAction = _.find( [...reportActions, parentReportAction], (action) => ReportUtils.canEditReportAction(action) && !ReportActionsUtils.isMoneyRequestAction(action), @@ -356,7 +353,7 @@ function ComposerWithSuggestions({ } } }, - [isKeyboardShown, isSmallScreenWidth, parentReportActions, report, reportActions, reportID, handleSendMessage, suggestionsRef, valueRef], + [isKeyboardShown, isSmallScreenWidth, parentReportAction, report, reportActions, reportID, handleSendMessage, suggestionsRef, valueRef], ); const onChangeText = useCallback( diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js index 1f6455ea6630..9573d4a4ff1a 100644 --- a/src/pages/home/report/ReportActionItem.js +++ b/src/pages/home/report/ReportActionItem.js @@ -645,6 +645,7 @@ function ReportActionItem(props) { @@ -793,6 +794,10 @@ export default compose( }, initialValue: {}, }, + policyReportFields: { + key: ({report}) => (report && 'policyID' in report ? `${ONYXKEYS.COLLECTION.POLICY_REPORT_FIELDS}${report.policyID}` : undefined), + initialValue: [], + }, emojiReactions: { key: ({action}) => `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS}${action.reportActionID}`, initialValue: {}, @@ -834,6 +839,8 @@ export default compose( prevProps.shouldHideThreadDividerLine === nextProps.shouldHideThreadDividerLine && lodashGet(prevProps.report, 'total', 0) === lodashGet(nextProps.report, 'total', 0) && lodashGet(prevProps.report, 'nonReimbursableTotal', 0) === lodashGet(nextProps.report, 'nonReimbursableTotal', 0) && - prevProps.linkedReportActionID === nextProps.linkedReportActionID, + prevProps.linkedReportActionID === nextProps.linkedReportActionID && + _.isEqual(prevProps.policyReportFields, nextProps.policyReportFields) && + _.isEqual(prevProps.report.reportFields, nextProps.report.reportFields), ), ); diff --git a/src/pages/home/report/ReportAttachments.js b/src/pages/home/report/ReportAttachments.tsx similarity index 55% rename from src/pages/home/report/ReportAttachments.js rename to src/pages/home/report/ReportAttachments.tsx index 8ecbb036a756..42ca51cabe0b 100644 --- a/src/pages/home/report/ReportAttachments.js +++ b/src/pages/home/report/ReportAttachments.tsx @@ -1,43 +1,47 @@ -import PropTypes from 'prop-types'; +import type {StackScreenProps} from '@react-navigation/stack'; import React, {useCallback} from 'react'; -import _ from 'underscore'; import AttachmentModal from '@components/AttachmentModal'; import ComposerFocusManager from '@libs/ComposerFocusManager'; import Navigation from '@libs/Navigation/Navigation'; +import type {AuthScreensParamList} from '@libs/Navigation/types'; import * as ReportUtils from '@libs/ReportUtils'; import ROUTES from '@src/ROUTES'; +import type SCREENS from '@src/SCREENS'; -const propTypes = { - /** Navigation route context info provided by react navigation */ - route: PropTypes.shape({ - /** Route specific parameters used on this screen */ - params: PropTypes.shape({ - /** The report ID which the attachment is associated with */ - reportID: PropTypes.string.isRequired, - /** The uri encoded source of the attachment */ - source: PropTypes.string.isRequired, - }).isRequired, - }).isRequired, +type File = { + name: string; }; -function ReportAttachments(props) { - const reportID = _.get(props, ['route', 'params', 'reportID']); +type Attachment = { + file: File; + hasBeenFlagged: boolean; + isAuthTokenRequired: boolean; + isReceipt: boolean; + reportActionID: string; + source: string; +}; + +type ReportAttachmentsProps = StackScreenProps; + +function ReportAttachments({route}: ReportAttachmentsProps) { + const reportID = route.params.reportID; const report = ReportUtils.getReport(reportID); // In native the imported images sources are of type number. Ref: https://reactnative.dev/docs/image#imagesource - const decodedSource = decodeURI(_.get(props, ['route', 'params', 'source'])); + const decodedSource = decodeURI(route.params.source); const source = Number(decodedSource) || decodedSource; const onCarouselAttachmentChange = useCallback( - (attachment) => { - const route = ROUTES.REPORT_ATTACHMENTS.getRoute(reportID, attachment.source); - Navigation.navigate(route); + (attachment: Attachment) => { + const routeToNavigate = ROUTES.REPORT_ATTACHMENTS.getRoute(reportID, attachment.source); + Navigation.navigate(routeToNavigate); }, [reportID], ); return ( ( - + {shouldShowSplitBillErrorMessage && ( diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js index 9edede770233..9567b17ecdf5 100755 --- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js +++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js @@ -8,6 +8,7 @@ import Button from '@components/Button'; import FormHelpMessage from '@components/FormHelpMessage'; import {usePersonalDetails} from '@components/OnyxProvider'; import {PressableWithFeedback} from '@components/Pressable'; +import ReferralProgramCTA from '@components/ReferralProgramCTA'; import SelectCircle from '@components/SelectCircle'; import SelectionList from '@components/SelectionList'; import useLocalize from '@hooks/useLocalize'; @@ -16,7 +17,6 @@ import useThemeStyles from '@hooks/useThemeStyles'; import * as Report from '@libs/actions/Report'; import * as DeviceCapabilities from '@libs/DeviceCapabilities'; import * as OptionsListUtils from '@libs/OptionsListUtils'; -import MoneyRequestReferralProgramCTA from '@pages/iou/MoneyRequestReferralProgramCTA'; import reportPropTypes from '@pages/reportPropTypes'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; @@ -285,7 +285,7 @@ function MoneyRequestParticipantsSelector({ () => ( - + {shouldShowSplitBillErrorMessage && ( diff --git a/src/pages/reportPropTypes.js b/src/pages/reportPropTypes.js index 329bf66f7275..3a056ee7c0a3 100644 --- a/src/pages/reportPropTypes.js +++ b/src/pages/reportPropTypes.js @@ -63,11 +63,14 @@ export default PropTypes.shape({ stateNum: PropTypes.oneOf(_.values(CONST.REPORT.STATE_NUM)), /** The status of the current report */ - statusNum: PropTypes.oneOf(_.values(CONST.REPORT.STATUS)), + statusNum: PropTypes.oneOf(_.values(CONST.REPORT.STATUS_NUM)), /** Which user role is capable of posting messages on the report */ writeCapability: PropTypes.oneOf(_.values(CONST.REPORT.WRITE_CAPABILITIES)), /** Field-specific pending states for offline UI status */ pendingFields: PropTypes.objectOf(PropTypes.string), + + /** Custom fields attached to the report */ + reportFields: PropTypes.objectOf(PropTypes.string), }); diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js index a4fc61910be2..1a526a9cdd9b 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.js +++ b/src/pages/tasks/TaskAssigneeSelectorModal.js @@ -184,29 +184,29 @@ function TaskAssigneeSelectorModal(props) { return sectionsList; }, [filteredCurrentUserOption, filteredPersonalDetails, filteredRecentReports, filteredUserToInvite, props]); - const selectReport = (option) => { - if (!option) { - return; - } - - // Check to see if we're creating a new task - // If there's no route params, we're creating a new task - if (!props.route.params && option.accountID) { - Task.setAssigneeValue(option.login, option.accountID, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); - return Navigation.goBack(ROUTES.NEW_TASK); - } - - // Check to see if we're editing a task and if so, update the assignee - if (report) { - if (option.accountID !== report.managerID) { - const assigneeChatReport = Task.setAssigneeValue(option.login, option.accountID, props.route.params.reportID, OptionsListUtils.isCurrentUser(option)); + const selectReport = useCallback( + (option) => { + if (!option) { + return; + } - // Pass through the selected assignee - Task.editTaskAssignee(report, props.session.accountID, option.login, option.accountID, assigneeChatReport); + // Check to see if we're editing a task and if so, update the assignee + if (report) { + if (option.accountID !== report.managerID) { + const assigneeChatReport = Task.setAssigneeValue(option.login, option.accountID, report.reportID, OptionsListUtils.isCurrentUser(option)); + + // Pass through the selected assignee + Task.editTaskAssignee(report, props.session.accountID, option.login, option.accountID, assigneeChatReport); + } + Navigation.dismissModal(report.reportID); + // If there's no report, we're creating a new task + } else if (option.accountID) { + Task.setAssigneeValue(option.login, option.accountID, props.task.shareDestination, OptionsListUtils.isCurrentUser(option)); + Navigation.goBack(ROUTES.NEW_TASK); } - return Navigation.dismissModal(report.reportID); - } - }; + }, + [props.session.accountID, props.task.shareDestination, report], + ); const isOpen = ReportUtils.isOpenTaskReport(report); const canModifyTask = Task.canModifyTask(report, props.currentUserPersonalDetails.accountID, lodashGet(props.rootParentReportPolicy, 'role', '')); diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts index f6af87038d00..7cc3c508d926 100644 --- a/src/types/onyx/Report.ts +++ b/src/types/onyx/Report.ts @@ -83,14 +83,11 @@ type Report = { /** ID of the chat report */ chatReportID?: string; - /** The state of the report */ - state?: ValueOf; - /** The state that the report is currently in */ stateNum?: ValueOf; /** The status of the current report */ - statusNum?: ValueOf; + statusNum?: ValueOf; /** Which user role is capable of posting messages on the report */ writeCapability?: WriteCapability; diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts index b2dc340af606..d5c0e19f9373 100644 --- a/src/types/onyx/ReportAction.ts +++ b/src/types/onyx/ReportAction.ts @@ -158,7 +158,7 @@ type ReportActionBase = { childManagerAccountID?: number; /** The status of the child report */ - childStatusNum?: ValueOf; + childStatusNum?: ValueOf; /** Report action child status name */ childStateNum?: ValueOf; diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js index 3ba19199c30a..5b304346f38f 100644 --- a/tests/actions/IOUTest.js +++ b/tests/actions/IOUTest.js @@ -1237,9 +1237,8 @@ describe('actions/IOU', () => { expect(chatReport.pendingFields).toBeFalsy(); expect(iouReport.pendingFields).toBeFalsy(); - // expect(iouReport.status).toBe(CONST.REPORT.STATUS.SUBMITTED); - // expect(iouReport.stateNum).toBe(CONST.REPORT.STATE_NUM.SUBMITTED); - // expect(iouReport.state).toBe(CONST.REPORT.STATE.SUBMITTED); + // expect(iouReport.status).toBe(CONST.REPORT.STATUS_NUM.SUBMITTED); + // expect(iouReport.stateNum).toBe(CONST.REPORT.STATE_NUM.APPROVED); resolve(); }, @@ -1306,9 +1305,8 @@ describe('actions/IOU', () => { expect(chatReport.iouReportID).toBeFalsy(); - // expect(iouReport.status).toBe(CONST.REPORT.STATUS.REIMBURSED); - // expect(iouReport.state).toBe(CONST.REPORT.STATE.MANUALREIMBURSED); - // expect(iouReport.stateNum).toBe(CONST.REPORT.STATE_NUM.SUBMITTED); + // expect(iouReport.status).toBe(CONST.REPORT.STATUS_NUM.REIMBURSED); + // expect(iouReport.stateNum).toBe(CONST.REPORT.STATE_NUM.APPROVED); resolve(); }, @@ -1356,9 +1354,8 @@ describe('actions/IOU', () => { expect(chatReport.iouReportID).toBeFalsy(); - // expect(iouReport.status).toBe(CONST.REPORT.STATUS.REIMBURSED); - // expect(iouReport.state).toBe(CONST.REPORT.STATE.MANUALREIMBURSED); - // expect(iouReport.stateNum).toBe(CONST.REPORT.STATE_NUM.SUBMITTED); + // expect(iouReport.status).toBe(CONST.REPORT.STATUS_NUM.REIMBURSED); + // expect(iouReport.stateNum).toBe(CONST.REPORT.STATE_NUM.APPROVED); resolve(); }, @@ -1770,9 +1767,8 @@ describe('actions/IOU', () => { expect.objectContaining({ lastMessageHtml: `paid $${amount / 100}.00 with Expensify`, lastMessageText: `paid $${amount / 100}.00 with Expensify`, - state: CONST.REPORT.STATE.SUBMITTED, - statusNum: CONST.REPORT.STATUS.REIMBURSED, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, + statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, }), ); expect(updatedChatReport).toEqual( diff --git a/tests/perf-test/OptionsSelector.perf-test.js b/tests/perf-test/OptionsSelector.perf-test.js index 3959ed87460a..b30169b8b53f 100644 --- a/tests/perf-test/OptionsSelector.perf-test.js +++ b/tests/perf-test/OptionsSelector.perf-test.js @@ -82,7 +82,7 @@ test('[OptionsSelector] should render 1 section', () => { measurePerformance(, {runs}); }); -test('[OptionsSelector] should render mutliple sections', () => { +test('[OptionsSelector] should render multiple sections', () => { const sections = generateSections(mutlipleSectionsConfig); measurePerformance(, {runs}); }); diff --git a/tests/perf-test/ReportActionsUtils.perf-test.ts b/tests/perf-test/ReportActionsUtils.perf-test.ts index ea3b48bacf47..2a96a5959942 100644 --- a/tests/perf-test/ReportActionsUtils.perf-test.ts +++ b/tests/perf-test/ReportActionsUtils.perf-test.ts @@ -9,18 +9,6 @@ import createCollection from '../utils/collections/createCollection'; import createRandomReportAction from '../utils/collections/reportActions'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; -beforeAll(() => - Onyx.init({ - keys: ONYXKEYS, - safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], - }), -); - -// Clear out Onyx after each test so that each test starts with a clean slate -afterEach(() => { - Onyx.clear(); -}); - const getMockedReportActionsMap = (reportsLength = 10, actionsPerReportLength = 100) => { const mockReportActions = Array.from({length: actionsPerReportLength}, (v, i) => { const reportActionKey = i + 1; @@ -49,120 +37,113 @@ const reportId = '1'; const runs = CONST.PERFORMANCE_TESTS.RUNS; -/** - * This function will be executed 20 times and the average time will be used on the comparison. - * It will fail based on the CI configuration around Reassure: - * @see /.github/workflows/reassurePerformanceTests.yml - * - * Max deviation on the duration is set to 20% at the time of writing. - * - * More on the measureFunction API: - * @see https://callstack.github.io/reassure/docs/api#measurefunction-function - */ -test('[ReportActionsUtils] getLastVisibleAction on 10k reportActions', async () => { - await Onyx.multiSet({ - ...mockedReportActionsMap, +describe('ReportActionsUtils', () => { + beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, + safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + }); + + Onyx.multiSet({ + ...mockedReportActionsMap, + }); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getLastVisibleAction(reportId), {runs}); -}); + afterAll(() => { + Onyx.clear(); + }); -test('[ReportActionsUtils] getLastVisibleAction on 10k reportActions with actionsToMerge', async () => { - const parentReportActionId = '1'; - const fakeParentAction = reportActions[parentReportActionId]; - const actionsToMerge = { - [parentReportActionId]: { - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - previousMessage: fakeParentAction.message, - message: [ - { - translationKey: '', - type: 'COMMENT', - html: '', - text: '', - isEdited: true, - isDeletedParentAction: true, - }, - ], - errors: null, - linkMetaData: [], - }, - } as unknown as ReportActions; - - await Onyx.multiSet({ - ...mockedReportActionsMap, + /** + * This function will be executed 20 times and the average time will be used on the comparison. + * It will fail based on the CI configuration around Reassure: + * @see /.github/workflows/reassurePerformanceTests.yml + * + * Max deviation on the duration is set to 20% at the time of writing. + * + * More on the measureFunction API: + * @see https://callstack.github.io/reassure/docs/api#measurefunction-function + */ + test('[ReportActionsUtils] getLastVisibleAction on 10k reportActions', async () => { + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getLastVisibleAction(reportId), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getLastVisibleAction(reportId, actionsToMerge), {runs}); -}); -test('[ReportActionsUtils] getMostRecentIOURequestActionID on 10k ReportActions', async () => { - const reportActionsArray = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); - await Onyx.multiSet({ - ...mockedReportActionsMap, + test('[ReportActionsUtils] getLastVisibleAction on 10k reportActions with actionsToMerge', async () => { + const parentReportActionId = '1'; + const fakeParentAction = reportActions[parentReportActionId]; + const actionsToMerge = { + [parentReportActionId]: { + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + previousMessage: fakeParentAction.message, + message: [ + { + translationKey: '', + type: 'COMMENT', + html: '', + text: '', + isEdited: true, + isDeletedParentAction: true, + }, + ], + errors: null, + linkMetaData: [], + }, + } as unknown as ReportActions; + + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getLastVisibleAction(reportId, actionsToMerge), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getMostRecentIOURequestActionID(reportActionsArray), {runs}); -}); -test('[ReportActionsUtils] getLastVisibleMessage on 10k ReportActions', async () => { - await Onyx.multiSet({ - ...mockedReportActionsMap, + test('[ReportActionsUtils] getMostRecentIOURequestActionID on 10k ReportActions', async () => { + const reportActionsArray = ReportActionsUtils.getSortedReportActionsForDisplay(reportActions); + + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getMostRecentIOURequestActionID(reportActionsArray), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getLastVisibleMessage(reportId), {runs}); -}); -test('[ReportActionsUtils] getLastVisibleMessage on 10k ReportActions with actionsToMerge', async () => { - const parentReportActionId = '1'; - const fakeParentAction = reportActions[parentReportActionId]; - const actionsToMerge = { - [parentReportActionId]: { - pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, - previousMessage: fakeParentAction.message, - message: [ - { - translationKey: '', - type: 'COMMENT', - html: '', - text: '', - isEdited: true, - isDeletedParentAction: true, - }, - ], - errors: null, - linkMetaData: [], - }, - } as unknown as ReportActions; - - await Onyx.multiSet({ - ...mockedReportActionsMap, + test('[ReportActionsUtils] getLastVisibleMessage on 10k ReportActions', async () => { + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getLastVisibleMessage(reportId), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getLastVisibleMessage(reportId, actionsToMerge), {runs}); -}); -test('[ReportActionsUtils] getSortedReportActionsForDisplay on 10k ReportActions', async () => { - await Onyx.multiSet({ - ...mockedReportActionsMap, + test('[ReportActionsUtils] getLastVisibleMessage on 10k ReportActions with actionsToMerge', async () => { + const parentReportActionId = '1'; + const fakeParentAction = reportActions[parentReportActionId]; + const actionsToMerge = { + [parentReportActionId]: { + pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE, + previousMessage: fakeParentAction.message, + message: [ + { + translationKey: '', + type: 'COMMENT', + html: '', + text: '', + isEdited: true, + isDeletedParentAction: true, + }, + ], + errors: null, + linkMetaData: [], + }, + } as unknown as ReportActions; + + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getLastVisibleMessage(reportId, actionsToMerge), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getSortedReportActionsForDisplay(reportActions), {runs}); -}); -test('[ReportActionsUtils] getLastClosedReportAction on 10k ReportActions', async () => { - await Onyx.multiSet({ - ...mockedReportActionsMap, + test('[ReportActionsUtils] getSortedReportActionsForDisplay on 10k ReportActions', async () => { + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getSortedReportActionsForDisplay(reportActions), {runs}); + }); + + test('[ReportActionsUtils] getLastClosedReportAction on 10k ReportActions', async () => { + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getLastClosedReportAction(reportActions), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getLastClosedReportAction(reportActions), {runs}); -}); -test('[ReportActionsUtils] getMostRecentReportActionLastModified', async () => { - await Onyx.multiSet({ - ...mockedReportActionsMap, + test('[ReportActionsUtils] getMostRecentReportActionLastModified', async () => { + await waitForBatchedUpdates(); + await measureFunction(() => ReportActionsUtils.getMostRecentReportActionLastModified(), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportActionsUtils.getMostRecentReportActionLastModified(), {runs}); }); diff --git a/tests/perf-test/ReportUtils.perf-test.ts b/tests/perf-test/ReportUtils.perf-test.ts index 62b911fb0417..30f874c669ab 100644 --- a/tests/perf-test/ReportUtils.perf-test.ts +++ b/tests/perf-test/ReportUtils.perf-test.ts @@ -13,19 +13,6 @@ import createRandomTransaction from '../utils/collections/transaction'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; const runs = CONST.PERFORMANCE_TESTS.RUNS; - -beforeAll(() => - Onyx.init({ - keys: ONYXKEYS, - safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], - }), -); - -// Clear out Onyx after each test so that each test starts with a clean state -afterEach(() => { - Onyx.clear(); -}); - const getMockedReports = (length = 500) => createCollection( (item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, @@ -50,195 +37,169 @@ const mockedReportsMap = getMockedReports(5000) as Record<`${typeof ONYXKEYS.COL const mockedPoliciesMap = getMockedPolicies(5000) as Record<`${typeof ONYXKEYS.COLLECTION.POLICY}`, Policy>; const participantAccountIDs = Array.from({length: 1000}, (v, i) => i + 1); -test('[ReportUtils] findLastAccessedReport on 2k reports and policies', async () => { - const ignoreDomainRooms = true; - const isFirstTimeNewExpensifyUser = true; - const reports = getMockedReports(2000); - const policies = getMockedPolicies(2000); - const openOnAdminRoom = true; - - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTimeNewExpensifyUser, openOnAdminRoom), {runs}); -}); +describe('ReportUtils', () => { + beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, + safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + }); + + Onyx.multiSet({ + ...mockedPoliciesMap, + ...mockedReportsMap, + }); + }); -test('[ReportUtils] canDeleteReportAction on 5k reports and policies', async () => { - const reportID = '1'; + afterAll(() => { + Onyx.clear(); + }); - const reportAction = {...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT} as unknown as ReportAction; + test('[ReportUtils] findLastAccessedReport on 2k reports and policies', async () => { + const ignoreDomainRooms = true; + const isFirstTimeNewExpensifyUser = true; + const reports = getMockedReports(2000); + const policies = getMockedPolicies(2000); + const openOnAdminRoom = true; - await Onyx.multiSet({ - ...mockedPoliciesMap, - ...mockedReportsMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTimeNewExpensifyUser, openOnAdminRoom), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.canDeleteReportAction(reportAction, reportID), {runs}); -}); + test('[ReportUtils] canDeleteReportAction on 5k reports and policies', async () => { + const reportID = '1'; + const reportAction = {...createRandomReportAction(1), actionName: CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT} as unknown as ReportAction; -test('[ReportUtils] getReportRecipientAccountID on 1k participants', async () => { - const report = {...createRandomReport(1), participantAccountIDs}; - const currentLoginAccountID = 1; - - await Onyx.multiSet({ - ...mockedReportsMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.canDeleteReportAction(reportAction, reportID), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getReportRecipientAccountIDs(report, currentLoginAccountID), {runs}); -}); - -test('[ReportUtils] getIconsForParticipants on 1k participants', async () => { - const participants = Array.from({length: 1000}, (v, i) => i + 1); + test('[ReportUtils] getReportRecipientAccountID on 1k participants', async () => { + const report = {...createRandomReport(1), participantAccountIDs}; + const currentLoginAccountID = 1; - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getIconsForParticipants(participants, personalDetails), {runs}); -}); + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getReportRecipientAccountIDs(report, currentLoginAccountID), {runs}); + }); -test('[ReportUtils] getIcons on 1k participants', async () => { - const report = {...createRandomReport(1), parentReportID: '1', parentReportActionID: '1', type: CONST.REPORT.TYPE.CHAT}; - const policy = createRandomPolicy(1); - const defaultIcon = null; - const defaultName = ''; - const defaultIconId = -1; + test('[ReportUtils] getIconsForParticipants on 1k participants', async () => { + const participants = Array.from({length: 1000}, (v, i) => i + 1); - await Onyx.multiSet({ - [ONYXKEYS.PERSONAL_DETAILS_LIST]: personalDetails, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getIconsForParticipants(participants, personalDetails), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getIcons(report, personalDetails, defaultIcon, defaultName, defaultIconId, policy), {runs}); -}); - -test('[ReportUtils] getDisplayNamesWithTooltips 1k participants', async () => { - const isMultipleParticipantReport = true; - const shouldFallbackToHidden = true; + test('[ReportUtils] getIcons on 1k participants', async () => { + const report = {...createRandomReport(1), parentReportID: '1', parentReportActionID: '1', type: CONST.REPORT.TYPE.CHAT}; + const policy = createRandomPolicy(1); + const defaultIcon = null; + const defaultName = ''; + const defaultIconId = -1; - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getDisplayNamesWithTooltips(personalDetails, isMultipleParticipantReport, shouldFallbackToHidden), {runs}); -}); + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getIcons(report, personalDetails, defaultIcon, defaultName, defaultIconId, policy), {runs}); + }); -test('[ReportUtils] getReportPreviewMessage on 5k policies', async () => { - const reportAction = createRandomReportAction(1); - const report = createRandomReport(1); - const policy = createRandomPolicy(1); - const shouldConsiderReceiptBeingScanned = true; - const isPreviewMessageForParentChatReport = true; + test('[ReportUtils] getDisplayNamesWithTooltips 1k participants', async () => { + const isMultipleParticipantReport = true; + const shouldFallbackToHidden = true; - await Onyx.multiSet({ - ...mockedPoliciesMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getDisplayNamesWithTooltips(personalDetails, isMultipleParticipantReport, shouldFallbackToHidden), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getReportPreviewMessage(report, reportAction, shouldConsiderReceiptBeingScanned, isPreviewMessageForParentChatReport, policy), {runs}); -}); + test('[ReportUtils] getReportPreviewMessage on 5k policies', async () => { + const reportAction = createRandomReportAction(1); + const report = createRandomReport(1); + const policy = createRandomPolicy(1); + const shouldConsiderReceiptBeingScanned = true; + const isPreviewMessageForParentChatReport = true; -test('[ReportUtils] getReportName on 1k participants', async () => { - const report = {...createRandomReport(1), chatType: undefined, participantAccountIDs}; - const policy = createRandomPolicy(1); + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getReportPreviewMessage(report, reportAction, shouldConsiderReceiptBeingScanned, isPreviewMessageForParentChatReport, policy), {runs}); + }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getReportName(report, policy), {runs}); -}); + test('[ReportUtils] getReportName on 1k participants', async () => { + const report = {...createRandomReport(1), chatType: undefined, participantAccountIDs}; + const policy = createRandomPolicy(1); -test('[ReportUtils] canShowReportRecipientLocalTime on 1k participants', async () => { - const report = {...createRandomReport(1), participantAccountIDs}; - const accountID = 1; - await Onyx.multiSet({ - ...mockedReportsMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getReportName(report, policy), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.canShowReportRecipientLocalTime(personalDetails, report, accountID), {runs}); -}); - -test('[ReportUtils] shouldReportBeInOptionList on 1k participant', async () => { - const report = {...createRandomReport(1), participantAccountIDs, type: CONST.REPORT.TYPE.CHAT}; - const currentReportId = '2'; - const isInGSDMode = true; - const betas = [CONST.BETAS.DEFAULT_ROOMS]; - const policies = getMockedPolicies(); + test('[ReportUtils] canShowReportRecipientLocalTime on 1k participants', async () => { + const report = {...createRandomReport(1), participantAccountIDs}; + const accountID = 1; - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies), {runs}); -}); + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.canShowReportRecipientLocalTime(personalDetails, report, accountID), {runs}); + }); -test('[ReportUtils] getWorkspaceIcon on 5k policies', async () => { - const report = createRandomReport(1); - const policy = createRandomPolicy(1); + test('[ReportUtils] shouldReportBeInOptionList on 1k participant', async () => { + const report = {...createRandomReport(1), participantAccountIDs, type: CONST.REPORT.TYPE.CHAT}; + const currentReportId = '2'; + const isInGSDMode = true; + const betas = [CONST.BETAS.DEFAULT_ROOMS]; + const policies = getMockedPolicies(); - await Onyx.multiSet({ - ...mockedPoliciesMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getWorkspaceIcon(report, policy), {runs}); -}); - -test('[ReportUtils] getMoneyRequestOptions on 1k participants', async () => { - const report = {...createRandomReport(1), type: CONST.REPORT.TYPE.CHAT, chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, isOwnPolicyExpenseChat: true}; - const policy = createRandomPolicy(1); - const reportParticipants = Array.from({length: 1000}, (v, i) => i + 1); + test('[ReportUtils] getWorkspaceIcon on 5k policies', async () => { + const report = createRandomReport(1); + const policy = createRandomPolicy(1); - await Onyx.multiSet({ - ...mockedPoliciesMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getWorkspaceIcon(report, policy), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getMoneyRequestOptions(report, policy, reportParticipants), {runs}); -}); - -test('[ReportUtils] getWorkspaceAvatar on 5k policies', async () => { - const report = createRandomReport(1); + test('[ReportUtils] getMoneyRequestOptions on 1k participants', async () => { + const report = {...createRandomReport(1), type: CONST.REPORT.TYPE.CHAT, chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT, isOwnPolicyExpenseChat: true}; + const policy = createRandomPolicy(1); + const reportParticipants = Array.from({length: 1000}, (v, i) => i + 1); - await Onyx.multiSet({ - ...mockedPoliciesMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getMoneyRequestOptions(report, policy, reportParticipants), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getWorkspaceAvatar(report), {runs}); -}); -test('[ReportUtils] getWorkspaceChat on 5k policies', async () => { - const policyID = '1'; - const accountsID = Array.from({length: 20}, (v, i) => i + 1); + test('[ReportUtils] getWorkspaceAvatar on 5k policies', async () => { + const report = createRandomReport(1); - await Onyx.multiSet({ - ...mockedReportsMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getWorkspaceAvatar(report), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getWorkspaceChats(policyID, accountsID), {runs}); -}); - -test('[ReportUtils] getTransactionDetails on 5k reports', async () => { - const transaction = createRandomTransaction(1); + test('[ReportUtils] getWorkspaceChat on 5k policies', async () => { + const policyID = '1'; + const accountsID = Array.from({length: 20}, (v, i) => i + 1); - await Onyx.multiSet({ - ...mockedReportsMap, + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getWorkspaceChats(policyID, accountsID), {runs}); }); - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getTransactionDetails(transaction, 'yyyy-MM-dd'), {runs}); -}); + test('[ReportUtils] getTransactionDetails on 5k reports', async () => { + const transaction = createRandomTransaction(1); + + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getTransactionDetails(transaction, 'yyyy-MM-dd'), {runs}); + }); -test('[ReportUtils] getIOUReportActionDisplayMessage on 5k policies', async () => { - const reportAction = { - ...createRandomReportAction(1), - actionName: CONST.REPORT.ACTIONS.TYPE.IOU, - originalMessage: { - IOUReportID: '1', - IOUTransactionID: '1', - amount: 100, - participantAccountID: 1, - currency: CONST.CURRENCY.USD, - type: CONST.IOU.REPORT_ACTION_TYPE.PAY, - paymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY, - }, - }; - - await Onyx.multiSet({ - ...mockedPoliciesMap, - }); - - await waitForBatchedUpdates(); - await measureFunction(() => ReportUtils.getIOUReportActionDisplayMessage(reportAction), {runs}); + test('[ReportUtils] getIOUReportActionDisplayMessage on 5k policies', async () => { + const reportAction = { + ...createRandomReportAction(1), + actionName: CONST.REPORT.ACTIONS.TYPE.IOU, + originalMessage: { + IOUReportID: '1', + IOUTransactionID: '1', + amount: 100, + participantAccountID: 1, + currency: CONST.CURRENCY.USD, + type: CONST.IOU.REPORT_ACTION_TYPE.PAY, + paymentType: CONST.IOU.PAYMENT_TYPE.EXPENSIFY, + }, + }; + + await waitForBatchedUpdates(); + await measureFunction(() => ReportUtils.getIOUReportActionDisplayMessage(reportAction), {runs}); + }); }); diff --git a/tests/perf-test/SidebarLinks.perf-test.js b/tests/perf-test/SidebarLinks.perf-test.js index 1f529b08e6b3..1bc674045c23 100644 --- a/tests/perf-test/SidebarLinks.perf-test.js +++ b/tests/perf-test/SidebarLinks.perf-test.js @@ -15,25 +15,6 @@ jest.mock('../../src/components/Icon/Expensicons'); jest.mock('@react-navigation/native'); -beforeAll(() => - Onyx.init({ - keys: ONYXKEYS, - safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], - registerStorageEventListener: () => {}, - }), -); - -// Initialize the network key for OfflineWithFeedback -beforeEach(() => { - wrapOnyxWithWaitForBatchedUpdates(Onyx); - return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); -}); - -// Clear out Onyx after each test so that each test starts with a clean slate -afterEach(() => { - Onyx.clear(); -}); - const getMockedReportsMap = (length = 100) => { const mockReports = Array.from({length}, (__, i) => { const reportID = i + 1; @@ -51,71 +32,81 @@ const mockedResponseMap = getMockedReportsMap(500); const runs = CONST.PERFORMANCE_TESTS.RUNS; -test('[SidebarLinks] should render Sidebar with 500 reports stored', () => { - const scenario = async () => { - // Query for the sidebar - await screen.findByTestId('lhn-options-list'); - /** - * Query for display names of participants [1, 2]. - * This will ensure that the sidebar renders a list of items. - */ - await screen.findAllByText('One, Two'); - }; - - return waitForBatchedUpdates() - .then(() => - Onyx.multiSet({ - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...mockedResponseMap, - }), - ) - .then(() => measurePerformance(, {scenario, runs})); -}); +describe('SidebarLinks', () => { + beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, + safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + registerStorageEventListener: () => {}, + }); + + Onyx.multiSet({ + [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, + [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], + [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, + [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, + ...mockedResponseMap, + }); + }); -test('[SidebarLinks] should scroll and click some of the items', () => { - const scenario = async () => { - const eventData = { - nativeEvent: { - contentOffset: { - y: variables.optionRowHeight * 5, - }, - contentSize: { - // Dimensions of the scrollable content - height: variables.optionRowHeight * 10, - width: 100, - }, - layoutMeasurement: { - // Dimensions of the device - height: variables.optionRowHeight * 5, - width: 100, + // Initialize the network key for OfflineWithFeedback + beforeEach(() => { + wrapOnyxWithWaitForBatchedUpdates(Onyx); + return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}); + }); + + afterAll(() => { + Onyx.clear(); + }); + + test('[SidebarLinks] should render Sidebar with 500 reports stored', async () => { + const scenario = async () => { + // Query for the sidebar + await screen.findByTestId('lhn-options-list'); + /** + * Query for display names of participants [1, 2]. + * This will ensure that the sidebar renders a list of items. + */ + await screen.findAllByText('One, Two'); + }; + + await waitForBatchedUpdates(); + await measurePerformance(, {scenario, runs}); + }); + + test('[SidebarLinks] should scroll and click some of the items', async () => { + const scenario = async () => { + const eventData = { + nativeEvent: { + contentOffset: { + y: variables.optionRowHeight * 5, + }, + contentSize: { + // Dimensions of the scrollable content + height: variables.optionRowHeight * 10, + width: 100, + }, + layoutMeasurement: { + // Dimensions of the device + height: variables.optionRowHeight * 5, + width: 100, + }, }, - }, + }; + + const lhnOptionsList = await screen.findByTestId('lhn-options-list'); + + fireEvent.scroll(lhnOptionsList, eventData); + // find elements that are currently visible in the viewport + const button1 = await screen.findByTestId('7'); + const button2 = await screen.findByTestId('8'); + fireEvent.press(button1); + fireEvent.press(button2); }; - const lhnOptionsList = await screen.findByTestId('lhn-options-list'); - - fireEvent.scroll(lhnOptionsList, eventData); - // find elements that are currently visible in the viewport - const button1 = await screen.findByTestId('7'); - const button2 = await screen.findByTestId('8'); - fireEvent.press(button1); - fireEvent.press(button2); - }; - - return waitForBatchedUpdates() - .then(() => - Onyx.multiSet({ - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails, - [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS], - [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD, - [ONYXKEYS.IS_LOADING_REPORT_DATA]: false, - ...mockedResponseMap, - }), - ) - .then(() => measurePerformance(, {scenario, runs})); + await waitForBatchedUpdates(); + + await measurePerformance(, {scenario, runs}); + }); }); diff --git a/tests/perf-test/SidebarUtils.perf-test.ts b/tests/perf-test/SidebarUtils.perf-test.ts index 6722cbf493a5..6ca81796d3ac 100644 --- a/tests/perf-test/SidebarUtils.perf-test.ts +++ b/tests/perf-test/SidebarUtils.perf-test.ts @@ -15,18 +15,6 @@ import createRandomReportAction from '../utils/collections/reportActions'; import createRandomReport from '../utils/collections/reports'; import waitForBatchedUpdates from '../utils/waitForBatchedUpdates'; -beforeAll(() => - Onyx.init({ - keys: ONYXKEYS, - safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], - }), -); - -// Clear out Onyx after each test so that each test starts with a clean slate -afterEach(() => { - Onyx.clear(); -}); - const getMockedReports = (length = 500) => createCollection( (item) => `${ONYXKEYS.COLLECTION.REPORT}${item.reportID}`, @@ -47,52 +35,61 @@ const personalDetails = createCollection( const mockedResponseMap = getMockedReports(5000) as Record<`${typeof ONYXKEYS.COLLECTION.REPORT}`, Report>; const runs = CONST.PERFORMANCE_TESTS.RUNS; -test('[SidebarUtils] getOptionData on 5k reports', async () => { - const report = createRandomReport(1); - const preferredLocale = 'en'; - const policy = createRandomPolicy(1); - const parentReportAction = createRandomReportAction(1); +describe('SidebarUtils', () => { + beforeAll(() => { + Onyx.init({ + keys: ONYXKEYS, + safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS], + }); - Onyx.multiSet({ - ...mockedResponseMap, + Onyx.multiSet({ + ...mockedResponseMap, + }); }); - await waitForBatchedUpdates(); - await measureFunction(() => SidebarUtils.getOptionData(report, reportActions, personalDetails, preferredLocale, policy, parentReportAction), {runs}); -}); + afterAll(() => { + Onyx.clear(); + }); -test('[SidebarUtils] getOrderedReportIDs on 5k reports', async () => { - const currentReportId = '1'; - const allReports = getMockedReports(); - const betas = [CONST.BETAS.DEFAULT_ROOMS]; + test('[SidebarUtils] getOptionData on 5k reports', async () => { + const report = createRandomReport(1); + const preferredLocale = 'en'; + const policy = createRandomPolicy(1); + const parentReportAction = createRandomReportAction(1); - const policies = createCollection( - (item) => `${ONYXKEYS.COLLECTION.POLICY}${item.id}`, - (index) => createRandomPolicy(index), - ); + await waitForBatchedUpdates(); + await measureFunction(() => SidebarUtils.getOptionData(report, reportActions, personalDetails, preferredLocale, policy, parentReportAction), {runs}); + }); + + test('[SidebarUtils] getOrderedReportIDs on 5k reports', async () => { + const currentReportId = '1'; + const allReports = getMockedReports(); + const betas = [CONST.BETAS.DEFAULT_ROOMS]; - const allReportActions = Object.fromEntries( - Object.keys(reportActions).map((key) => [ - key, - [ - { - errors: reportActions[key].errors ?? [], - message: [ - { - moderationDecision: { - decision: reportActions[key].message?.[0]?.moderationDecision?.decision, + const policies = createCollection( + (item) => `${ONYXKEYS.COLLECTION.POLICY}${item.id}`, + (index) => createRandomPolicy(index), + ); + + const allReportActions = Object.fromEntries( + Object.keys(reportActions).map((key) => [ + key, + [ + { + errors: reportActions[key].errors ?? [], + message: [ + { + moderationDecision: { + decision: reportActions[key].message?.[0]?.moderationDecision?.decision, + }, }, - }, - ], - }, - ], - ]), - ) as unknown as OnyxCollection; + ], + }, + ], + ]), + ) as unknown as OnyxCollection; - Onyx.multiSet({ - ...mockedResponseMap, + await waitForBatchedUpdates(); + await measureFunction(() => SidebarUtils.getOrderedReportIDs(currentReportId, allReports, betas, policies, CONST.PRIORITY_MODE.DEFAULT, allReportActions), {runs}); }); - - await waitForBatchedUpdates(); - await measureFunction(() => SidebarUtils.getOrderedReportIDs(currentReportId, allReports, betas, policies, CONST.PRIORITY_MODE.DEFAULT, allReportActions), {runs}); }); diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index d700aa4724f1..c9e8053e3146 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -149,8 +149,8 @@ describe('ReportUtils', () => { test('Archived', () => { const archivedAdminsRoom = { ...baseAdminsRoom, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; expect(ReportUtils.getReportName(archivedAdminsRoom)).toBe('#admins (archived)'); @@ -172,8 +172,8 @@ describe('ReportUtils', () => { test('Archived', () => { const archivedPolicyRoom = { ...baseUserCreatedRoom, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; expect(ReportUtils.getReportName(archivedPolicyRoom)).toBe('#VikingsChat (archived)'); @@ -213,8 +213,8 @@ describe('ReportUtils', () => { ownerAccountID: 1, policyID: policy.policyID, oldPolicyName: policy.name, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; test('as member', () => { @@ -307,7 +307,7 @@ describe('ReportUtils', () => { managerID: currentUserAccountID, isUnreadWithMention: false, stateNum: CONST.REPORT.STATE_NUM.OPEN, - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, }; expect(ReportUtils.requiresAttentionFromCurrentUser(report)).toBe(true); }); @@ -368,7 +368,7 @@ describe('ReportUtils', () => { const report = { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.IOU, - statusNum: CONST.REPORT.STATUS.REIMBURSED, + statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, }; const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, {}, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); @@ -378,8 +378,8 @@ describe('ReportUtils', () => { const report = { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.EXPENSE, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, - statusNum: CONST.REPORT.STATUS.APPROVED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, + statusNum: CONST.REPORT.STATUS_NUM.APPROVED, }; const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, {}, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); @@ -389,7 +389,7 @@ describe('ReportUtils', () => { const report = { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.EXPENSE, - statusNum: CONST.REPORT.STATUS.REIMBURSED, + statusNum: CONST.REPORT.STATUS_NUM.REIMBURSED, }; const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, {}, [currentUserAccountID]); expect(moneyRequestOptions.length).toBe(0); @@ -419,8 +419,8 @@ describe('ReportUtils', () => { const report = { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.EXPENSE, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, parentReportID: '101', }; const paidPolicy = { @@ -508,7 +508,7 @@ describe('ReportUtils', () => { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.EXPENSE, stateNum: CONST.REPORT.STATE_NUM.OPEN, - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, parentReportID: '103', }; const paidPolicy = { @@ -523,9 +523,8 @@ describe('ReportUtils', () => { const report = { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.IOU, - state: CONST.REPORT.STATE.SUBMITTED, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, {}, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(1); @@ -536,9 +535,8 @@ describe('ReportUtils', () => { const report = { ...LHNTestUtils.getFakeReport(), type: CONST.REPORT.TYPE.IOU, - state: CONST.REPORT.STATE.SUBMITTED, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(report, {}, [currentUserAccountID, participantsAccountIDs[0]]); expect(moneyRequestOptions.length).toBe(1); diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js index 088e5a1af4d0..83ccf3e92752 100644 --- a/tests/unit/SidebarFilterTest.js +++ b/tests/unit/SidebarFilterTest.js @@ -457,20 +457,20 @@ describe('Sidebar', () => { // Given an archived chat report, an archived default policy room, and an archived user created policy room const archivedReport = { ...LHNTestUtils.getFakeReport([1, 2]), - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; const archivedPolicyRoomReport = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ANNOUNCE, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; const archivedUserCreatedPolicyRoomReport = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; LHNTestUtils.getDefaultRenderedSidebarLinks(); @@ -681,8 +681,8 @@ describe('Sidebar', () => { const report = { ...LHNTestUtils.getFakeReport(), lastVisibleActionCreated: '2022-11-22 03:48:27.267', - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; // Given the user is in all betas @@ -732,8 +732,8 @@ describe('Sidebar', () => { // Given an archived report that has all comments read const report = { ...LHNTestUtils.getFakeReport(), - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; // Given the user is in all betas @@ -781,8 +781,8 @@ describe('Sidebar', () => { const report = { ...LHNTestUtils.getFakeReport(), isPinned: false, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; // Given the user is in all betas @@ -826,8 +826,8 @@ describe('Sidebar', () => { // Given an archived report that is not the active report const report = { ...LHNTestUtils.getFakeReport(), - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; // Given the user is in all betas diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js index 4d49cb3ad516..ed50c32559a7 100644 --- a/tests/unit/SidebarOrderTest.js +++ b/tests/unit/SidebarOrderTest.js @@ -255,7 +255,7 @@ describe('Sidebar', () => { reportName: taskReportName, managerID: 2, stateNum: CONST.REPORT.STATE_NUM.OPEN, - statusNum: CONST.REPORT.STATUS.OPEN, + statusNum: CONST.REPORT.STATUS_NUM.OPEN, }; // Each report has at least one ADDCOMMENT action so should be rendered in the LNH @@ -313,8 +313,8 @@ describe('Sidebar', () => { total: 10000, currency: 'USD', chatReportID: report3.reportID, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; report3.iouReportID = iouReport.reportID; @@ -374,9 +374,8 @@ describe('Sidebar', () => { policyName: 'Workspace', total: -10000, currency: 'USD', - state: CONST.REPORT.STATE.SUBMITTED, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, chatReportID: report3.reportID, parentReportID: report3.reportID, }; @@ -575,9 +574,8 @@ describe('Sidebar', () => { total: 10000, currency: 'USD', chatReportID: report3.reportID, - state: CONST.REPORT.STATE.SUBMITTED, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; report3.iouReportID = iouReport.reportID; const currentReportId = report2.reportID; @@ -740,8 +738,8 @@ describe('Sidebar', () => { const report1 = { ...LHNTestUtils.getFakeReport([1, 2]), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; const report2 = LHNTestUtils.getFakeReport([3, 4]); const report3 = LHNTestUtils.getFakeReport([5, 6]); @@ -837,8 +835,8 @@ describe('Sidebar', () => { const report1 = { ...LHNTestUtils.getFakeReport([1, 2], 3, true), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; const report2 = LHNTestUtils.getFakeReport([3, 4], 2, true); const report3 = LHNTestUtils.getFakeReport([5, 6], 1, true); @@ -914,8 +912,8 @@ describe('Sidebar', () => { total: 10000, currency: 'USD', chatReportID: report3.reportID, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; const iouReport2 = { ...LHNTestUtils.getFakeReport([9, 10]), @@ -926,8 +924,8 @@ describe('Sidebar', () => { total: 10000, currency: 'USD', chatReportID: report3.reportID, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; const iouReport3 = { ...LHNTestUtils.getFakeReport([11, 12]), @@ -938,8 +936,8 @@ describe('Sidebar', () => { total: 100000, currency: 'USD', chatReportID: report3.reportID, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; const iouReport4 = { ...LHNTestUtils.getFakeReport([11, 12]), @@ -950,8 +948,8 @@ describe('Sidebar', () => { total: 10000, currency: 'USD', chatReportID: report3.reportID, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; const iouReport5 = { ...LHNTestUtils.getFakeReport([11, 12]), @@ -962,8 +960,8 @@ describe('Sidebar', () => { total: 10000, currency: 'USD', chatReportID: report3.reportID, - stateNum: CONST.REPORT.STATE_NUM.PROCESSING, - statusNum: CONST.REPORT.STATUS.SUBMITTED, + stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.SUBMITTED, }; report1.iouReportID = iouReport1.reportID; diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js index 56009ee382d5..1101c5732707 100644 --- a/tests/unit/SidebarTest.js +++ b/tests/unit/SidebarTest.js @@ -51,8 +51,8 @@ describe('Sidebar', () => { const report = { ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3, true), chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; // Given the user is in all betas @@ -86,8 +86,8 @@ describe('Sidebar', () => { ...LHNTestUtils.getFakeReport(['email1@test.com', 'email2@test.com'], 3, true), policyName: 'Vikings Policy', chatType: CONST.REPORT.CHAT_TYPE.POLICY_ROOM, - statusNum: CONST.REPORT.STATUS.CLOSED, - stateNum: CONST.REPORT.STATE_NUM.SUBMITTED, + statusNum: CONST.REPORT.STATUS_NUM.CLOSED, + stateNum: CONST.REPORT.STATE_NUM.APPROVED, }; const action = { ...LHNTestUtils.getFakeReportAction('email1@test.com', 3, true), diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js index 535fb018dbc3..900a7852c92d 100644 --- a/tests/utils/LHNTestUtils.js +++ b/tests/utils/LHNTestUtils.js @@ -209,8 +209,8 @@ function getAdvancedFakeReport(isArchived, isUserCreatedPolicyRoom, hasAddWorksp ...getFakeReport([1, 2], 0, isUnread), type: CONST.REPORT.TYPE.CHAT, chatType: isUserCreatedPolicyRoom ? CONST.REPORT.CHAT_TYPE.POLICY_ROOM : CONST.REPORT.CHAT_TYPE.POLICY_ADMINS, - statusNum: isArchived ? CONST.REPORT.STATUS.CLOSED : 0, - stateNum: isArchived ? CONST.REPORT.STATE_NUM.SUBMITTED : 0, + statusNum: isArchived ? CONST.REPORT.STATUS_NUM.CLOSED : 0, + stateNum: isArchived ? CONST.REPORT.STATE_NUM.APPROVED : 0, errorFields: hasAddWorkspaceError ? {addWorkspaceRoom: 'blah'} : null, isPinned, hasDraft, diff --git a/web/index.html b/web/index.html index 967873fe586c..7c02614d17b2 100644 --- a/web/index.html +++ b/web/index.html @@ -96,6 +96,11 @@ caret-color: #ffffff; } + /* Customize Plaid iframe */ + [id^="plaid-link-iframe"] { + color-scheme: dark !important; + } + /* Prevent autofill from overlapping with the input label in Chrome */ div:has(input:-webkit-autofill, input[chrome-autofilled]) > label { transform: translateY(var(--active-label-translate-y)) scale(var(--active-label-scale)) !important;