diff --git a/android/app/build.gradle b/android/app/build.gradle index 829f980431a4..e179b59f4b30 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 1001043601 - versionName "1.4.36-1" + versionCode 1001043702 + versionName "1.4.37-2" } flavorDimensions "default" diff --git a/android/app/src/main/res/values/colors.xml b/android/app/src/main/res/values/colors.xml index b4d8c2181b0b..94065c5b9d19 100644 --- a/android/app/src/main/res/values/colors.xml +++ b/android/app/src/main/res/values/colors.xml @@ -1,4 +1,5 @@ + #03D47C #FFFFFF #03D47C diff --git a/docs/articles/expensify-classic/getting-started/Individual-Users.md b/docs/articles/expensify-classic/getting-started/Individual-Users.md deleted file mode 100644 index 12029f80388b..000000000000 --- a/docs/articles/expensify-classic/getting-started/Individual-Users.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: Individual Users -description: Learn how Expensify can help you track and submit your personal or self-employed business expenses. ---- -# Overview -If you're an individual using Expensify, the Track and Submit plans are designed to assist self-employed users in effectively managing both their personal and business finances. - -# How to use the Track plan - -The Track plan is tailored for solo Expensify users who don't require expense submission to others. Individuals or sole proprietors can choose the Track plan to customize their Individual Workspace to align with their personal expense tracking requirements. - -You can select the Track plan from the Workspace settings. Navigate to **Settings > Workspace > Individual > *[Workspace Name]* > Plan** to select Track. -You can also do this from the Pricing page at https://www.expensify.com/pricing. - -The Track plan includes a predefined set of categories designed to align with IRS Schedule C expense categories. However, you have the flexibility to add extra categories as needed. For a more detailed breakdown, you can also set up tags to create another layer of coding. - -The Track plan offers 25 free SmartScans per month. If you require more than 25 SmartScans, you can upgrade to a Monthly Individual subscription at a cost of $4.99 USD per month. - -# How to use the Submit plan -The Submit plan is designed for individuals who need to keep track of their expenses and share them with someone else, such as their boss, accountant, or even a housemate. It's specifically tailored for single users who want to both track and submit their expenses efficiently. - -You can select the Track plan from the Workspace settings. Navigate to **Settings > Workspaces > Individual > *[Workspace Name]* > Plan** to select "Submit" or from the Pricing page at https://www.expensify.com/pricing. - -You will select who your expenses get sent to under **Settings > Workspace > Individual > *[Workspace Name]* > Reports**. If the recipient already has an Expensify account, they'll be able to see the report directly in the Expensify app. Otherwise, non-Expensify users will receive a PDF copy of the report attached to the email so it can be processed. - -The Submit plan includes a predefined set of categories designed to align with IRS Schedule C expense categories. However, you have the flexibility to add extra categories as needed. For a more detailed breakdown, you can also set up tags to create another layer of coding. - -The Submit plan offers 25 free SmartScans per month.If you require more than 25 SmartScans, you can upgrade to a Monthly Individual subscription at a cost of $4.99 USD per month. - -# FAQ - -## Who should use the Track plan? -An individual who wants to store receipts, look to track spending by category to help with budgeting and a self-employed user who needs to track receipts and mileage for tax purposes. - -## Who should use the Submit plan? -An individual who seeks to utilize the features of the track plan to monitor their expenses while also requiring the ability to submit those expenses to someone else. - -## How can I keep track of personal and business expenses in the same account? -You have the capability to create distinct "business" and "personal" tags and assign them to your expenses for proper categorization. By doing so, you can effectively code your expenses based on their nature. Additionally, you can utilize filters to ensure that you only view the expenses that are relevant to your specific needs, whether they are business-related or personal. - -## How can I export expenses for tax purposes? -From the expense page, you have the option to select all of your expenses and export them to a CSV (Comma-Separated Values) file. This CSV file can be conveniently imported directly into your tax software for easier tax preparation. - diff --git a/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md b/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md index 099f381e6010..a31b972e683c 100644 --- a/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md +++ b/docs/articles/expensify-classic/getting-started/Join-your-company's-workspace.md @@ -212,7 +212,6 @@ Once you’ve created your expenses, they may be automatically added to an expen
  • Attach PDF: Select this checkbox to attach a copy of your report to the email.
  • Tap Submit.
  • - {% include end-option.html %} @@ -255,4 +254,4 @@ Add an extra layer of security to help keep your financial data safe and secure When you log in to Expensify in the future, you’ll open your authenticator app to get the code and enter it into Expensify. A new code regenerates every few seconds, so the code is always different. If the code time runs out, you can generate a new code as needed. - \ No newline at end of file + diff --git a/docs/redirects.csv b/docs/redirects.csv index df615431533f..988b07d729f0 100644 --- a/docs/redirects.csv +++ b/docs/redirects.csv @@ -49,3 +49,4 @@ https://community.expensify.com/discussion/5793/how-to-connect-your-personal-car https://community.expensify.com/discussion/4826/how-to-set-your-annual-subscription-size,https://help.expensify.com/articles/expensify-classic/billing-and-subscriptions/Annual-Subscription https://community.expensify.com/discussion/5667/deep-dive-how-does-the-annual-subscription-billing-work,https://help.expensify.com/articles/expensify-classic/billing-and-subscriptions/Annual-Subscription https://help.expensify.com/expensify-classic/hubs/getting-started/plan-types,https://www.expensify.com/pricing +https://help.expensify.com/articles/expensify-classic/getting-started/Employees,https://help.expensify.com/articles/expensify-classic/getting-started/Join-your-company's-workspace diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index d4ee691ab6da..b529bbbcd100 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.4.36 + 1.4.37 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.4.36.1 + 1.4.37.2 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensify/RCTBootSplash.h b/ios/NewExpensify/RCTBootSplash.h index df38a5eb35bf..c25c676feb4a 100644 --- a/ios/NewExpensify/RCTBootSplash.h +++ b/ios/NewExpensify/RCTBootSplash.h @@ -10,6 +10,7 @@ @interface RCTBootSplash : NSObject ++ (void)invalidateBootSplash; + (void)initWithStoryboard:(NSString * _Nonnull)storyboardName rootView:(RCTRootView * _Nullable)rootView; diff --git a/ios/NewExpensify/RCTBootSplash.m b/ios/NewExpensify/RCTBootSplash.m index bceac70efdcf..6c2baaed4ee0 100644 --- a/ios/NewExpensify/RCTBootSplash.m +++ b/ios/NewExpensify/RCTBootSplash.m @@ -26,6 +26,12 @@ - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } ++ (void)invalidateBootSplash { + _resolverQueue = nil; + _rootView = nil; + _nativeHidden = false; +} + + (void)initWithStoryboard:(NSString * _Nonnull)storyboardName rootView:(RCTRootView * _Nullable)rootView { if (rootView == nil || _rootView != nil || RCTRunningInAppExtension()) @@ -102,6 +108,9 @@ + (void)onContentDidAppear { block:^(NSTimer * _Nonnull timer) { [timer invalidate]; + if (_rootView == nil) + return; + if (_resolverQueue == nil) _resolverQueue = [[NSMutableArray alloc] init]; diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index b40af313f3e5..af5704061df2 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.4.36 + 1.4.37 CFBundleSignature ???? CFBundleVersion - 1.4.36.1 + 1.4.37.2 diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist index b5da9f0caaa4..8209491d19ff 100644 --- a/ios/NotificationServiceExtension/Info.plist +++ b/ios/NotificationServiceExtension/Info.plist @@ -11,9 +11,9 @@ CFBundleName $(PRODUCT_NAME) CFBundleShortVersionString - 1.4.36 + 1.4.37 CFBundleVersion - 1.4.36.1 + 1.4.37.2 NSExtension NSExtensionPointIdentifier diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 584dd5636773..1664c982ce50 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1453,7 +1453,7 @@ PODS: - SDWebImage/Core (~> 5.17) - SocketRocket (0.6.1) - Turf (2.7.0) - - VisionCamera (2.16.2): + - VisionCamera (2.16.5): - React - React-callinvoker - React-Core @@ -1922,7 +1922,7 @@ SPEC CHECKSUMS: react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b react-native-key-command: 5af6ee30ff4932f78da6a2109017549042932aa5 react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d - react-native-live-markdown: 1ca4275d4dba8eebb736a005148f24a8224f54d9 + react-native-live-markdown: 81ac491b913cb8541a06586adcdc159ab1b86fb5 react-native-netinfo: 8a7fd3f7130ef4ad2fb4276d5c9f8d3f28d2df3d react-native-pager-view: 02a5c4962530f7efc10dd51ee9cdabeff5e6c631 react-native-pdf: b4ca3d37a9a86d9165287741c8b2ef4d8940c00e @@ -1980,7 +1980,7 @@ SPEC CHECKSUMS: SDWebImageWebPCoder: af09429398d99d524cae2fe00f6f0f6e491ed102 SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 Turf: 13d1a92d969ca0311bbc26e8356cca178ce95da2 - VisionCamera: 7d13aae043ffb38b224a0f725d1e23ca9c190fe7 + VisionCamera: fda554d8751e395effcc87749f8b7c198c1031be Yoga: 13c8ef87792450193e117976337b8527b49e8c03 PODFILE CHECKSUM: 0ccbb4f2406893c6e9f266dc1e7470dcd72885d2 diff --git a/package-lock.json b/package-lock.json index e9ba0d44e663..072684aa77c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "new.expensify", - "version": "1.4.36-1", + "version": "1.4.37-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.4.36-1", + "version": "1.4.37-2", "hasInstallScript": true, "license": "MIT", "dependencies": { "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "git+ssh://git@github.com/Expensify/react-native-live-markdown.git#c316611781f19815caebfed5540e0faf2a274785", + "@expensify/react-native-live-markdown": "git+ssh://git@github.com/Expensify/react-native-live-markdown.git#2ed4240336e50abb4a7fa9ff6a3c180f8bc9ce5b", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-getcanonicallocales": "^2.2.0", @@ -21,11 +21,11 @@ "@formatjs/intl-pluralrules": "^5.2.2", "@gorhom/portal": "^1.0.14", "@invertase/react-native-apple-authentication": "^2.2.2", - "@kie/act-js": "^2.0.1", + "@kie/act-js": "^2.6.0", "@kie/mock-github": "^1.0.0", "@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52", "@onfido/react-native-sdk": "8.3.0", - "@react-native-async-storage/async-storage": "^1.19.5", + "@react-native-async-storage/async-storage": "1.21.0", "@react-native-camera-roll/camera-roll": "5.4.0", "@react-native-clipboard/clipboard": "^1.12.1", "@react-native-community/geolocation": "^3.0.6", @@ -113,7 +113,7 @@ "react-native-tab-view": "^3.5.2", "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "3.8.0", - "react-native-vision-camera": "^2.16.2", + "react-native-vision-camera": "2.16.5", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-webview": "13.6.3", @@ -3352,8 +3352,8 @@ }, "node_modules/@expensify/react-native-live-markdown": { "version": "0.1.0", - "resolved": "git+ssh://git@github.com/Expensify/react-native-live-markdown.git#c316611781f19815caebfed5540e0faf2a274785", - "integrity": "sha512-yF3oaBhqWQonl12LPELYLsgfmqCsGg2bu15g/h8XzVX3f/nzfPtrWE/ax2lWEIpIjk4/+aEu/VGNKLnlehjTxQ==", + "resolved": "git+ssh://git@github.com/Expensify/react-native-live-markdown.git#2ed4240336e50abb4a7fa9ff6a3c180f8bc9ce5b", + "integrity": "sha512-i+HIsCFL9cdma+saH/KN2llTGqEb2DQttEJKozdm4fvcie9Ce2/q7XNDZo6nIYTbIVXPDLKPDmWLXqXTgLBKDQ==", "license": "MIT", "workspaces": [ "example" @@ -7186,9 +7186,9 @@ "dev": true }, "node_modules/@kie/act-js": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@kie/act-js/-/act-js-2.3.0.tgz", - "integrity": "sha512-Q9k0b05uA46jXKWmVfoGDW+0xsCcE7QPiHi8IH7h41P36DujHKBj4k28RCeIEx3IwUCxYHKwubN8DH4Vzc9XcA==", + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@kie/act-js/-/act-js-2.6.0.tgz", + "integrity": "sha512-AkBTAsvRWLMvJ0cBiZ0+XUC9QVNwJzcZFxZJV2i+oaXPirafCyzzmT7+cJ4t0YNFMkgM+EEN7XMWr2MgoSyOvg==", "hasInstallScript": true, "dependencies": { "@kie/mock-github": "^2.0.0", @@ -32351,9 +32351,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", "funding": [ { "type": "individual", @@ -45329,9 +45329,9 @@ } }, "node_modules/react-native-vision-camera": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-2.16.2.tgz", - "integrity": "sha512-QIpG33l3QB0AkTfX/ccRknwNRu1APNUkokVKF1lpRO2+tBnkXnGL0UapgXg5u9KIONZtrpupeDeO+J5B2TeQVw==", + "version": "2.16.5", + "resolved": "https://registry.npmjs.org/react-native-vision-camera/-/react-native-vision-camera-2.16.5.tgz", + "integrity": "sha512-MzXhNd597OyMQSEGhqWI4DufWkdr7PR7U9B30E3gXnln7cnvjMVIp4j3eIW9BIrgvEyUcEeL7nZM5NLhTmO/fA==", "peerDependencies": { "react": "*", "react-native": "*" diff --git a/package.json b/package.json index 68c815ad328a..e08a8bdcb70a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.4.36-1", + "version": "1.4.37-2", "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.", @@ -59,7 +59,7 @@ }, "dependencies": { "@dotlottie/react-player": "^1.6.3", - "@expensify/react-native-live-markdown": "git+ssh://git@github.com/Expensify/react-native-live-markdown.git#c316611781f19815caebfed5540e0faf2a274785", + "@expensify/react-native-live-markdown": "git+ssh://git@github.com/Expensify/react-native-live-markdown.git#2ed4240336e50abb4a7fa9ff6a3c180f8bc9ce5b", "@expo/metro-runtime": "~3.1.1", "@formatjs/intl-datetimeformat": "^6.10.0", "@formatjs/intl-getcanonicallocales": "^2.2.0", @@ -69,11 +69,11 @@ "@formatjs/intl-pluralrules": "^5.2.2", "@gorhom/portal": "^1.0.14", "@invertase/react-native-apple-authentication": "^2.2.2", - "@kie/act-js": "^2.0.1", + "@kie/act-js": "^2.6.0", "@kie/mock-github": "^1.0.0", "@oguzhnatly/react-native-image-manipulator": "github:Expensify/react-native-image-manipulator#5cdae3d4455b03a04c57f50be3863e2fe6c92c52", "@onfido/react-native-sdk": "8.3.0", - "@react-native-async-storage/async-storage": "^1.19.5", + "@react-native-async-storage/async-storage": "1.21.0", "@react-native-camera-roll/camera-roll": "5.4.0", "@react-native-clipboard/clipboard": "^1.12.1", "@react-native-community/geolocation": "^3.0.6", @@ -161,7 +161,7 @@ "react-native-tab-view": "^3.5.2", "react-native-url-polyfill": "^2.0.0", "react-native-view-shot": "3.8.0", - "react-native-vision-camera": "^2.16.2", + "react-native-vision-camera": "2.16.5", "react-native-web": "^0.19.9", "react-native-web-linear-gradient": "^1.1.2", "react-native-webview": "13.6.3", diff --git a/patches/@oguzhnatly+react-native-image-manipulator+1.0.5.patch b/patches/@oguzhnatly+react-native-image-manipulator+1.0.5.patch index c613a47a3072..d5a390daf201 100644 --- a/patches/@oguzhnatly+react-native-image-manipulator+1.0.5.patch +++ b/patches/@oguzhnatly+react-native-image-manipulator+1.0.5.patch @@ -7,13 +7,13 @@ index 3a1a548..fe030bb 100644 android { - compileSdkVersion 28 -+ compileSdkVersion 30 ++ compileSdkVersion 34 buildToolsVersion "28.0.3" defaultConfig { minSdkVersion 16 - targetSdkVersion 28 -+ targetSdkVersion 30 ++ targetSdkVersion 34 versionCode 1 versionName "1.0" } diff --git a/patches/@react-native-camera-roll+camera-roll+5.4.0.patch b/patches/@react-native-camera-roll+camera-roll+5.4.0.patch new file mode 100644 index 000000000000..f0429bc10125 --- /dev/null +++ b/patches/@react-native-camera-roll+camera-roll+5.4.0.patch @@ -0,0 +1,15 @@ +diff --git a/node_modules/@react-native-camera-roll/camera-roll/android/build.gradle b/node_modules/@react-native-camera-roll/camera-roll/android/build.gradle +index 3f76132..63dc946 100644 +--- a/node_modules/@react-native-camera-roll/camera-roll/android/build.gradle ++++ b/node_modules/@react-native-camera-roll/camera-roll/android/build.gradle +@@ -81,7 +81,9 @@ def findNodeModulePath(baseDir, packageName) { + } + + def resolveReactNativeDirectory() { +- def reactNative = file("${findNodeModulePath(rootProject.projectDir, "react-native")}") ++ def projectDir = this.hasProperty('reactNativeProject') ? this.reactNativeProject : rootProject.projectDir ++ def modulePath = file(projectDir); ++ def reactNative = file("${findNodeModulePath(modulePath, 'react-native')}") + if (reactNative.exists()) { + return reactNative + } diff --git a/patches/@react-native-community+cli-platform-android+12.3.0.patch b/patches/@react-native-community+cli-platform-android+12.3.0.patch new file mode 100644 index 000000000000..d94baf0f9c6e --- /dev/null +++ b/patches/@react-native-community+cli-platform-android+12.3.0.patch @@ -0,0 +1,52 @@ +diff --git a/node_modules/@react-native-community/cli-platform-android/native_modules.gradle b/node_modules/@react-native-community/cli-platform-android/native_modules.gradle +index bbfa7f7..ed53872 100644 +--- a/node_modules/@react-native-community/cli-platform-android/native_modules.gradle ++++ b/node_modules/@react-native-community/cli-platform-android/native_modules.gradle +@@ -140,6 +140,7 @@ class ReactNativeModules { + private Logger logger + private String packageName + private File root ++ private File rnRoot + private ArrayList> reactNativeModules + private ArrayList unstable_reactLegacyComponentNames + private HashMap reactNativeModulesBuildVariants +@@ -147,9 +148,10 @@ class ReactNativeModules { + + private static String LOG_PREFIX = ":ReactNative:" + +- ReactNativeModules(Logger logger, File root) { ++ ReactNativeModules(Logger logger, File root, File rnRoot) { + this.logger = logger + this.root = root ++ this.rnRoot = rnRoot + + def (nativeModules, reactNativeModulesBuildVariants, androidProject, reactNativeVersion) = this.getReactNativeConfig() + this.reactNativeModules = nativeModules +@@ -416,10 +418,10 @@ class ReactNativeModules { + */ + def cliResolveScript = "try {console.log(require('@react-native-community/cli').bin);} catch (e) {console.log(require('react-native/cli').bin);}" + String[] nodeCommand = ["node", "-e", cliResolveScript] +- def cliPath = this.getCommandOutput(nodeCommand, this.root) ++ def cliPath = this.getCommandOutput(nodeCommand, this.rnRoot) + + String[] reactNativeConfigCommand = ["node", cliPath, "config"] +- def reactNativeConfigOutput = this.getCommandOutput(reactNativeConfigCommand, this.root) ++ def reactNativeConfigOutput = this.getCommandOutput(reactNativeConfigCommand, this.rnRoot) + + def json + try { +@@ -486,7 +488,13 @@ class ReactNativeModules { + */ + def projectRoot = rootProject.projectDir + +-def autoModules = new ReactNativeModules(logger, projectRoot) ++def autoModules ++ ++if(this.hasProperty('reactNativeProject')){ ++ autoModules = new ReactNativeModules(logger, projectRoot, new File(projectRoot, reactNativeProject)) ++} else { ++ autoModules = new ReactNativeModules(logger, projectRoot, projectRoot) ++} + + def reactNativeVersionRequireNewArchEnabled(autoModules) { + def rnVersion = autoModules.reactNativeVersion diff --git a/patches/@react-native-community+cli-platform-ios+12.3.0.patch b/patches/@react-native-community+cli-platform-ios+12.3.0.patch new file mode 100644 index 000000000000..cfae504e44fa --- /dev/null +++ b/patches/@react-native-community+cli-platform-ios+12.3.0.patch @@ -0,0 +1,52 @@ +diff --git a/node_modules/@react-native-community/cli-platform-ios/native_modules.rb b/node_modules/@react-native-community/cli-platform-ios/native_modules.rb +index 82f537c..f5e2cda 100644 +--- a/node_modules/@react-native-community/cli-platform-ios/native_modules.rb ++++ b/node_modules/@react-native-community/cli-platform-ios/native_modules.rb +@@ -12,7 +12,7 @@ + require 'pathname' + require 'cocoapods' + +-def use_native_modules!(config = nil) ++def updateConfig(config = nil) + if (config.is_a? String) + Pod::UI.warn("Passing custom root to use_native_modules! is deprecated.", + [ +@@ -24,7 +24,6 @@ def use_native_modules!(config = nil) + # Resolving the path the RN CLI. The `@react-native-community/cli` module may not be there for certain package managers, so we fall back to resolving it through `react-native` package, that's always present in RN projects + cli_resolve_script = "try {console.log(require('@react-native-community/cli').bin);} catch (e) {console.log(require('react-native/cli').bin);}" + cli_bin = Pod::Executable.execute_command("node", ["-e", cli_resolve_script], true).strip +- + if (!config) + json = [] + +@@ -36,10 +35,30 @@ def use_native_modules!(config = nil) + + config = JSON.parse(json.join("\n")) + end ++end ++ ++def use_native_modules!(config = nil) ++ if (ENV['REACT_NATIVE_DIR']) ++ Dir.chdir(ENV['REACT_NATIVE_DIR']) do ++ config = updateConfig(config) ++ end ++ else ++ config = updateConfig(config) ++ end + + project_root = Pathname.new(config["project"]["ios"]["sourceDir"]) + ++ if(ENV["PROJECT_ROOT_DIR"]) ++ project_root = File.join(Dir.pwd, ENV["PROJECT_ROOT_DIR"]) ++ ++ end ++ + packages = config["dependencies"] ++ ++ if (ENV["NO_FLIPPER"]) ++ packages = {**packages, "react-native-flipper" => {"platforms" => {"ios" => nil}}} ++ end ++ + found_pods = [] + + packages.each do |package_name, package| diff --git a/patches/@react-native-firebase+analytics+12.9.3.patch b/patches/@react-native-firebase+analytics+12.9.3.patch new file mode 100644 index 000000000000..74d3e2a8005a --- /dev/null +++ b/patches/@react-native-firebase+analytics+12.9.3.patch @@ -0,0 +1,18 @@ +diff --git a/node_modules/@react-native-firebase/analytics/android/build.gradle b/node_modules/@react-native-firebase/analytics/android/build.gradle +index d223ebf..821b730 100644 +--- a/node_modules/@react-native-firebase/analytics/android/build.gradle ++++ b/node_modules/@react-native-firebase/analytics/android/build.gradle +@@ -45,6 +45,8 @@ if (coreVersionDetected != coreVersionRequired) { + } + } + ++apply plugin: 'com.android.library' ++ + project.ext { + set('react-native', [ + versions: [ +@@ -144,4 +146,3 @@ dependencies { + ReactNative.shared.applyPackageVersion() + ReactNative.shared.applyDefaultExcludes() + ReactNative.module.applyAndroidVersions() +-ReactNative.module.applyReactNativeDependency("api") diff --git a/patches/@react-native-firebase+app+12.9.3.patch b/patches/@react-native-firebase+app+12.9.3.patch new file mode 100644 index 000000000000..312fdacf4432 --- /dev/null +++ b/patches/@react-native-firebase+app+12.9.3.patch @@ -0,0 +1,25 @@ +diff --git a/node_modules/@react-native-firebase/app/android/build.gradle b/node_modules/@react-native-firebase/app/android/build.gradle +index 05f629a..7c36693 100644 +--- a/node_modules/@react-native-firebase/app/android/build.gradle ++++ b/node_modules/@react-native-firebase/app/android/build.gradle +@@ -18,6 +18,7 @@ buildscript { + + plugins { + id "io.invertase.gradle.build" version "1.5" ++ id 'com.android.library' + } + + def packageJson = PackageJson.getForProject(project) +@@ -91,6 +92,7 @@ repositories { + } + + dependencies { ++ api 'com.facebook.react:react-native:+' + implementation platform("com.google.firebase:firebase-bom:${ReactNative.ext.getVersion("firebase", "bom")}") + implementation "com.google.firebase:firebase-common" + implementation "com.google.android.gms:play-services-auth:${ReactNative.ext.getVersion("play", "play-services-auth")}" +@@ -99,4 +101,3 @@ dependencies { + ReactNative.shared.applyPackageVersion() + ReactNative.shared.applyDefaultExcludes() + ReactNative.module.applyAndroidVersions() +-ReactNative.module.applyReactNativeDependency("api") diff --git a/patches/@react-native-firebase+crashlytics+12.9.3.patch b/patches/@react-native-firebase+crashlytics+12.9.3.patch new file mode 100644 index 000000000000..560f462731dc --- /dev/null +++ b/patches/@react-native-firebase+crashlytics+12.9.3.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/@react-native-firebase/crashlytics/android/build.gradle b/node_modules/@react-native-firebase/crashlytics/android/build.gradle +index 6b6de57..9b89ae7 100644 +--- a/node_modules/@react-native-firebase/crashlytics/android/build.gradle ++++ b/node_modules/@react-native-firebase/crashlytics/android/build.gradle +@@ -18,6 +18,7 @@ buildscript { + + plugins { + id "io.invertase.gradle.build" version "1.5" ++ id 'com.android.library' + } + + def appProject +@@ -92,4 +93,3 @@ dependencies { + ReactNative.shared.applyPackageVersion() + ReactNative.shared.applyDefaultExcludes() + ReactNative.module.applyAndroidVersions() +-ReactNative.module.applyReactNativeDependency("api") diff --git a/patches/@react-native-firebase+perf+12.9.3.patch b/patches/@react-native-firebase+perf+12.9.3.patch new file mode 100644 index 000000000000..7d8a9f4f23b5 --- /dev/null +++ b/patches/@react-native-firebase+perf+12.9.3.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/@react-native-firebase/perf/android/build.gradle b/node_modules/@react-native-firebase/perf/android/build.gradle +index b4a9c7b..5835e3d 100644 +--- a/node_modules/@react-native-firebase/perf/android/build.gradle ++++ b/node_modules/@react-native-firebase/perf/android/build.gradle +@@ -19,6 +19,7 @@ buildscript { + + plugins { + id "io.invertase.gradle.build" version "1.5" ++ id 'com.android.library' + } + + def appProject +@@ -129,4 +130,3 @@ dependencies { + ReactNative.shared.applyPackageVersion() + ReactNative.shared.applyDefaultExcludes() + ReactNative.module.applyAndroidVersions() +-ReactNative.module.applyReactNativeDependency("api") diff --git a/patches/expo+50.0.4.patch b/patches/expo+50.0.4.patch new file mode 100644 index 000000000000..95157e1d73c6 --- /dev/null +++ b/patches/expo+50.0.4.patch @@ -0,0 +1,10 @@ +diff --git a/node_modules/expo/scripts/autolinking.gradle b/node_modules/expo/scripts/autolinking.gradle +index 60d6ef8..3ed90a4 100644 +--- a/node_modules/expo/scripts/autolinking.gradle ++++ b/node_modules/expo/scripts/autolinking.gradle +@@ -1,4 +1,4 @@ + // Resolve `expo` > `expo-modules-autolinking` dependency chain + def autolinkingPath = ["node", "--print", "require.resolve('expo-modules-autolinking/package.json', { paths: [require.resolve('expo/package.json')] })"].execute(null, rootDir).text.trim() +-apply from: new File(autolinkingPath, "../scripts/android/autolinking_implementation.gradle"); + ++apply from: hasProperty("reactNativeProject") ? file('../../expo-modules-autolinking/scripts/android/autolinking_implementation.gradle') : new File(autolinkingPath, "../scripts/android/autolinking_implementation.gradle"); diff --git a/patches/expo-modules-autolinking+1.10.2.patch b/patches/expo-modules-autolinking+1.10.2.patch new file mode 100644 index 000000000000..4b68007ba125 --- /dev/null +++ b/patches/expo-modules-autolinking+1.10.2.patch @@ -0,0 +1,40 @@ +diff --git a/node_modules/expo-modules-autolinking/scripts/android/autolinking_implementation.gradle b/node_modules/expo-modules-autolinking/scripts/android/autolinking_implementation.gradle +index 92f1fd6..ada01ad 100644 +--- a/node_modules/expo-modules-autolinking/scripts/android/autolinking_implementation.gradle ++++ b/node_modules/expo-modules-autolinking/scripts/android/autolinking_implementation.gradle +@@ -149,12 +149,13 @@ class ExpoAutolinkingManager { + } + + static private String[] convertOptionsToCommandArgs(String command, Map options) { ++ def expoPath = options.searchPaths ? "../react-native/node_modules/expo" : "expo" + String[] args = [ + 'node', + '--no-warnings', + '--eval', + // Resolve the `expo` > `expo-modules-autolinking` chain from the project root +- 'require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo\')] }))(process.argv.slice(1))', ++ "require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'${expoPath}\')] }))(process.argv.slice(1))", + '--', + command, + '--platform', +diff --git a/node_modules/expo-modules-autolinking/scripts/ios/project_integrator.rb b/node_modules/expo-modules-autolinking/scripts/ios/project_integrator.rb +index 5d46f1e..3db7b89 100644 +--- a/node_modules/expo-modules-autolinking/scripts/ios/project_integrator.rb ++++ b/node_modules/expo-modules-autolinking/scripts/ios/project_integrator.rb +@@ -215,6 +215,7 @@ module Expo + args = autolinking_manager.base_command_args.map { |arg| "\"#{arg}\"" } + platform = autolinking_manager.platform_name.downcase + package_names = autolinking_manager.packages_to_generate.map { |package| "\"#{package.name}\"" } ++ expo_path = ENV['REACT_NATIVE_DIR'] ? "#{ENV['REACT_NATIVE_DIR']}/node_modules/expo" : "expo" + + <<~SUPPORT_SCRIPT + #!/usr/bin/env bash +@@ -262,7 +263,7 @@ module Expo + + with_node \\ + --no-warnings \\ +- --eval "require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'expo/package.json\')] }))(process.argv.slice(1))" \\ ++ --eval "require(require.resolve(\'expo-modules-autolinking\', { paths: [require.resolve(\'#{expo_path}/package.json\')] }))(process.argv.slice(1))" \\ + generate-modules-provider #{args.join(' ')} \\ + --target "#{modules_provider_path}" \\ + --platform "apple" \\ diff --git a/patches/expo-modules-core+1.11.8.patch b/patches/expo-modules-core+1.11.8.patch new file mode 100644 index 000000000000..fe8c5ed7b9cc --- /dev/null +++ b/patches/expo-modules-core+1.11.8.patch @@ -0,0 +1,16 @@ +diff --git a/node_modules/expo-modules-core/android/build.gradle b/node_modules/expo-modules-core/android/build.gradle +index 3603ffd..1599a69 100644 +--- a/node_modules/expo-modules-core/android/build.gradle ++++ b/node_modules/expo-modules-core/android/build.gradle +@@ -53,9 +53,10 @@ def isExpoModulesCoreTests = { + }.call() + + def REACT_NATIVE_BUILD_FROM_SOURCE = findProject(":packages:react-native:ReactAndroid") != null ++def FALLBACK_REACT_NATIVE_DIR = hasProperty("reactNativeProject") ? file('../../react-native') : new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).parent + def REACT_NATIVE_DIR = REACT_NATIVE_BUILD_FROM_SOURCE + ? findProject(":packages:react-native:ReactAndroid").getProjectDir().parent +- : new File(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim()).parent ++ : FALLBACK_REACT_NATIVE_DIR + + def reactProperties = new Properties() + file("$REACT_NATIVE_DIR/ReactAndroid/gradle.properties").withInputStream { reactProperties.load(it) } diff --git a/patches/react-native-pdf+6.7.3.patch b/patches/react-native-pdf+6.7.3.patch new file mode 100644 index 000000000000..63024e7d4c1f --- /dev/null +++ b/patches/react-native-pdf+6.7.3.patch @@ -0,0 +1,23 @@ +diff --git a/node_modules/react-native-pdf/index.js b/node_modules/react-native-pdf/index.js +index c05de52..bea7af8 100644 +--- a/node_modules/react-native-pdf/index.js ++++ b/node_modules/react-native-pdf/index.js +@@ -367,11 +367,17 @@ export default class Pdf extends Component { + message[4] = message.splice(4).join('|'); + } + if (message[0] === 'loadComplete') { ++ let tableContents; ++ try { ++ tableContents = message[4]&&JSON.parse(message[4]); ++ } catch(e) { ++ tableContents = message[4]; ++ } + this.props.onLoadComplete && this.props.onLoadComplete(Number(message[1]), this.state.path, { + width: Number(message[2]), + height: Number(message[3]), + }, +- message[4]&&JSON.parse(message[4])); ++ tableContents); + } else if (message[0] === 'pageChanged') { + this.props.onPageChanged && this.props.onPageChanged(Number(message[1]), Number(message[2])); + } else if (message[0] === 'error') { diff --git a/patches/react-native-reanimated+3.6.1.patch b/patches/react-native-reanimated+3.6.1.patch new file mode 100644 index 000000000000..3b40360d5860 --- /dev/null +++ b/patches/react-native-reanimated+3.6.1.patch @@ -0,0 +1,17 @@ +diff --git a/node_modules/react-native-reanimated/scripts/reanimated_utils.rb b/node_modules/react-native-reanimated/scripts/reanimated_utils.rb +index af0935f..ccd2a9e 100644 +--- a/node_modules/react-native-reanimated/scripts/reanimated_utils.rb ++++ b/node_modules/react-native-reanimated/scripts/reanimated_utils.rb +@@ -17,7 +17,11 @@ def find_config() + :react_native_common_dir => nil, + } + +- react_native_node_modules_dir = File.join(File.dirname(`cd "#{Pod::Config.instance.installation_root.to_s}" && node --print "require.resolve('react-native/package.json')"`), '..') ++ root_project = Pod::Config.instance.installation_root.to_s ++ if(ENV['PROJECT_ROOT_DIR']) ++ root_project = ENV['PROJECT_ROOT_DIR'] ++ end ++ react_native_node_modules_dir = File.join(File.dirname(`cd "#{root_project}" && node --print "require.resolve('react-native/package.json')"`), '..') + react_native_json = try_to_parse_react_native_package_json(react_native_node_modules_dir) + + if react_native_json == nil diff --git a/patches/react-native-vision-camera+2.16.2+001+fix-boost-dependency.patch b/patches/react-native-vision-camera+2.16.5+001+fix-boost-dependency.patch similarity index 56% rename from patches/react-native-vision-camera+2.16.2+001+fix-boost-dependency.patch rename to patches/react-native-vision-camera+2.16.5+001+fix-boost-dependency.patch index ef4fbf1d5084..3afc4573985d 100644 --- a/patches/react-native-vision-camera+2.16.2+001+fix-boost-dependency.patch +++ b/patches/react-native-vision-camera+2.16.5+001+fix-boost-dependency.patch @@ -1,8 +1,17 @@ diff --git a/node_modules/react-native-vision-camera/android/build.gradle b/node_modules/react-native-vision-camera/android/build.gradle -index d308e15..2d87d8e 100644 +index ddfa243..bafffc3 100644 --- a/node_modules/react-native-vision-camera/android/build.gradle +++ b/node_modules/react-native-vision-camera/android/build.gradle -@@ -347,7 +347,7 @@ if (ENABLE_FRAME_PROCESSORS) { +@@ -334,7 +334,7 @@ if (ENABLE_FRAME_PROCESSORS) { + def thirdPartyVersions = new Properties() + thirdPartyVersions.load(new FileInputStream(thirdPartyVersionsFile)) + +- def BOOST_VERSION = thirdPartyVersions["BOOST_VERSION"] ++ def BOOST_VERSION = thirdPartyVersions["BOOST_VERSION"] ?: "1.83.0" + def boost_file = new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz") + def DOUBLE_CONVERSION_VERSION = thirdPartyVersions["DOUBLE_CONVERSION_VERSION"] + def double_conversion_file = new File(downloadsDir, "double-conversion-${DOUBLE_CONVERSION_VERSION}.tar.gz") +@@ -352,7 +352,7 @@ if (ENABLE_FRAME_PROCESSORS) { task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) { def transformedVersion = BOOST_VERSION.replace("_", ".") diff --git a/patches/react-native-vision-camera+2.16.2.patch b/patches/react-native-vision-camera+2.16.5.patch similarity index 100% rename from patches/react-native-vision-camera+2.16.2.patch rename to patches/react-native-vision-camera+2.16.5.patch diff --git a/src/App.js b/src/App.js index 8045f4eb30ad..b750d12e8c28 100644 --- a/src/App.js +++ b/src/App.js @@ -1,4 +1,5 @@ import {PortalProvider} from '@gorhom/portal'; +import PropTypes from 'prop-types'; import React from 'react'; import {LogBox} from 'react-native'; import {GestureHandlerRootView} from 'react-native-gesture-handler'; @@ -29,8 +30,18 @@ import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop'; import OnyxUpdateManager from './libs/actions/OnyxUpdateManager'; import * as Session from './libs/actions/Session'; import * as Environment from './libs/Environment/Environment'; +import InitialUrlContext from './libs/InitialUrlContext'; import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext'; +const propTypes = { + /** Initial url that may be passed as deeplink from Hybrid App */ + url: PropTypes.string, +}; + +const defaultProps = { + url: undefined, +}; + // For easier debugging and development, when we are in web we expose Onyx to the window, so you can more easily set data into Onyx if (window && Environment.isDevelopment()) { window.Onyx = Onyx; @@ -46,44 +57,48 @@ LogBox.ignoreLogs([ const fill = {flex: 1}; -function App() { +function App({url}) { useDefaultDragAndDrop(); OnyxUpdateManager(); return ( - - - - - - - - - - + + + + + + + + + + + + ); } +App.propTypes = propTypes; +App.defaultProps = defaultProps; App.displayName = 'App'; export default App; diff --git a/src/CONST.ts b/src/CONST.ts index b27923465a1f..6c726cde12f7 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -46,6 +46,8 @@ const CONST = { IN: 'in', OUT: 'out', }, + // Multiplier for gyroscope animation in order to make it a bit more subtle + ANIMATION_GYROSCOPE_VALUE: 0.4, BACKGROUND_IMAGE_TRANSITION_DURATION: 1000, ARROW_HIDE_DELAY: 3000, @@ -100,6 +102,10 @@ const CONST = { MAX_LENGTH: 40, }, + REPORT_DESCRIPTION: { + MAX_LENGTH: 1024, + }, + PULL_REQUEST_NUMBER, MERCHANT_NAME_MAX_LENGTH: 255, @@ -146,7 +152,7 @@ const CONST = { CONTAINER_MINHEIGHT: 500, VIEW_HEIGHT: 275, }, - MONEY_REPORT: { + MONEY_OR_TASK_REPORT: { SMALL_SCREEN: { IMAGE_HEIGHT: 300, CONTAINER_MINHEIGHT: 280, @@ -1431,6 +1437,8 @@ const CONST = { EMOJI: /[\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu, // eslint-disable-next-line max-len, no-misleading-character-class EMOJIS: /[\p{Extended_Pictographic}](\u200D[\p{Extended_Pictographic}]|[\u{1F3FB}-\u{1F3FF}]|[\u{E0020}-\u{E007F}]|\uFE0F|\u20E3)*|[\u{1F1E6}-\u{1F1FF}]{2}|[#*0-9]\uFE0F?\u20E3/gu, + // eslint-disable-next-line max-len, no-misleading-character-class + EMOJI_SKIN_TONES: /[\u{1f3fb}-\u{1f3ff}]/gu, TAX_ID: /^\d{9}$/, NON_NUMERIC: /\D/g, @@ -1588,7 +1596,6 @@ const CONST = { INVITE: 'invite', SETTINGS: 'settings', LEAVE_ROOM: 'leaveRoom', - WELCOME_MESSAGE: 'welcomeMessage', PRIVATE_NOTES: 'privateNotes', }, EDIT_REQUEST_FIELD: { diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts index 7328fb2543ad..9fed8b69db79 100755 --- a/src/ONYXKEYS.ts +++ b/src/ONYXKEYS.ts @@ -313,8 +313,8 @@ const ONYXKEYS = { DISPLAY_NAME_FORM_DRAFT: 'displayNameFormDraft', ROOM_NAME_FORM: 'roomNameForm', ROOM_NAME_FORM_DRAFT: 'roomNameFormDraft', - WELCOME_MESSAGE_FORM: 'welcomeMessageForm', - WELCOME_MESSAGE_FORM_DRAFT: 'welcomeMessageFormDraft', + REPORT_DESCRIPTION_FORM: 'reportDescriptionForm', + REPORT_DESCRIPTION_FORM_DRAFT: 'reportDescriptionFormDraft', LEGAL_NAME_FORM: 'legalNameForm', LEGAL_NAME_FORM_DRAFT: 'legalNameFormDraft', WORKSPACE_INVITE_MESSAGE_FORM: 'workspaceInviteMessageForm', @@ -408,7 +408,7 @@ type OnyxValues = { [ONYXKEYS.NVP_PRIVATE_PUSH_NOTIFICATION_ID]: string; [ONYXKEYS.NVP_TRY_FOCUS_MODE]: boolean; [ONYXKEYS.FOCUS_MODE_NOTIFICATION]: boolean; - [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: Record; + [ONYXKEYS.NVP_LAST_PAYMENT_METHOD]: OnyxTypes.LastPaymentMethod; [ONYXKEYS.NVP_RECENT_WAYPOINTS]: OnyxTypes.RecentWaypoint[]; [ONYXKEYS.NVP_HAS_DISMISSED_IDLE_PANEL]: boolean; [ONYXKEYS.NVP_INTRO_SELECTED]: OnyxTypes.IntroSelected; @@ -480,9 +480,9 @@ type OnyxValues = { [ONYXKEYS.COLLECTION.TRANSACTION]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolations; + [ONYXKEYS.COLLECTION.SPLIT_TRANSACTION_DRAFT]: OnyxTypes.Transaction; [ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS]: OnyxTypes.RecentlyUsedTags; [ONYXKEYS.COLLECTION.SELECTED_TAB]: string; - [ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS]: OnyxTypes.TransactionViolation[]; [ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT]: string; [ONYXKEYS.COLLECTION.NEXT_STEP]: OnyxTypes.ReportNextStep; @@ -499,10 +499,10 @@ type OnyxValues = { [ONYXKEYS.FORMS.PROFILE_SETTINGS_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.DISPLAY_NAME_FORM]: OnyxTypes.DisplayNameForm; [ONYXKEYS.FORMS.DISPLAY_NAME_FORM_DRAFT]: OnyxTypes.DisplayNameForm; - [ONYXKEYS.FORMS.ROOM_NAME_FORM]: OnyxTypes.Form; - [ONYXKEYS.FORMS.ROOM_NAME_FORM_DRAFT]: OnyxTypes.Form; - [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM]: OnyxTypes.Form; - [ONYXKEYS.FORMS.WELCOME_MESSAGE_FORM_DRAFT]: OnyxTypes.Form; + [ONYXKEYS.FORMS.ROOM_NAME_FORM]: OnyxTypes.RoomNameForm; + [ONYXKEYS.FORMS.ROOM_NAME_FORM_DRAFT]: OnyxTypes.RoomNameForm; + [ONYXKEYS.FORMS.REPORT_DESCRIPTION_FORM]: OnyxTypes.Form; + [ONYXKEYS.FORMS.REPORT_DESCRIPTION_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.LEGAL_NAME_FORM]: OnyxTypes.Form; [ONYXKEYS.FORMS.LEGAL_NAME_FORM_DRAFT]: OnyxTypes.Form; [ONYXKEYS.FORMS.WORKSPACE_INVITE_MESSAGE_FORM]: OnyxTypes.Form; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index 78b97f8dcde0..e987c5b94d7d 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -214,10 +214,6 @@ const ROUTES = { route: 'r/:reportID/settings/who-can-post', getRoute: (reportID: string) => `r/${reportID}/settings/who-can-post` as const, }, - REPORT_WELCOME_MESSAGE: { - route: 'r/:reportID/welcomeMessage', - getRoute: (reportID: string) => `r/${reportID}/welcomeMessage` as const, - }, SPLIT_BILL_DETAILS: { route: 'r/:reportID/split/:reportActionID', getRoute: (reportID: string, reportActionID: string) => `r/${reportID}/split/${reportActionID}` as const, @@ -235,7 +231,7 @@ const ROUTES = { route: 'r/:reportID/title', getRoute: (reportID: string) => `r/${reportID}/title` as const, }, - TASK_DESCRIPTION: { + REPORT_DESCRIPTION: { route: 'r/:reportID/description', getRoute: (reportID: string) => `r/${reportID}/description` as const, }, @@ -497,7 +493,16 @@ const ROUTES = { PROCESS_MONEY_REQUEST_HOLD: 'hold-request-educational', } as const; -export {getUrlWithBackToParam}; +/** + * Proxy routes can be used to generate a correct url with dynamic values + * + * It will be used by HybridApp, that has no access to methods generating dynamic routes in NewDot + */ +const HYBRID_APP_ROUTES = { + MONEY_REQUEST_CREATE: '/request/new/scan', +} as const; + +export {getUrlWithBackToParam, HYBRID_APP_ROUTES}; export default ROUTES; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -517,4 +522,6 @@ type RouteIsPlainString = IsEqual; */ type Route = RouteIsPlainString extends true ? never : AllRoutes; -export type {Route}; +type HybridAppRoute = (typeof HYBRID_APP_ROUTES)[keyof typeof HYBRID_APP_ROUTES]; + +export type {Route, HybridAppRoute}; diff --git a/src/SCREENS.ts b/src/SCREENS.ts index a64bf328ff28..e2f0e9745561 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -100,7 +100,7 @@ const SCREENS = { PROFILE: 'Profile', REPORT_DETAILS: 'Report_Details', REPORT_SETTINGS: 'Report_Settings', - REPORT_WELCOME_MESSAGE: 'Report_WelcomeMessage', + REPORT_DESCRIPTION: 'Report_Description', PARTICIPANTS: 'Participants', MONEY_REQUEST: 'MoneyRequest', NEW_TASK: 'NewTask', @@ -183,7 +183,6 @@ const SCREENS = { TASK: { TITLE: 'Task_Title', - DESCRIPTION: 'Task_Description', ASSIGNEE: 'Task_Assignee', }, @@ -242,7 +241,7 @@ const SCREENS = { DETAILS_ROOT: 'Details_Root', PROFILE_ROOT: 'Profile_Root', PROCESS_MONEY_REQUEST_HOLD_ROOT: 'ProcessMoneyRequestHold_Root', - REPORT_WELCOME_MESSAGE_ROOT: 'Report_WelcomeMessage_Root', + REPORT_DESCRIPTION_ROOT: 'Report_Description_Root', REPORT_PARTICIPANTS_ROOT: 'ReportParticipants_Root', ROOM_MEMBERS_ROOT: 'RoomMembers_Root', ROOM_INVITE_ROOT: 'RoomInvite_Root', diff --git a/src/components/AttachmentModal.tsx b/src/components/AttachmentModal.tsx index 90954c63b751..78ef72ac3536 100755 --- a/src/components/AttachmentModal.tsx +++ b/src/components/AttachmentModal.tsx @@ -283,7 +283,7 @@ function AttachmentModal({ * Detach the receipt and close the modal. */ const deleteAndCloseModal = useCallback(() => { - IOU.detachReceipt(transaction?.transactionID); + IOU.detachReceipt(transaction?.transactionID ?? ''); setIsDeleteReceiptConfirmModalVisible(false); Navigation.dismissModal(report?.reportID); }, [transaction, report]); diff --git a/src/components/ButtonWithDropdownMenu.tsx b/src/components/ButtonWithDropdownMenu.tsx index 676912de6b60..9466da601825 100644 --- a/src/components/ButtonWithDropdownMenu.tsx +++ b/src/components/ButtonWithDropdownMenu.tsx @@ -9,15 +9,18 @@ import useThemeStyles from '@hooks/useThemeStyles'; import useWindowDimensions from '@hooks/useWindowDimensions'; import type {AnchorPosition} from '@styles/index'; import CONST from '@src/CONST'; +import type AnchorAlignment from '@src/types/utils/AnchorAlignment'; +import type DeepValueOf from '@src/types/utils/DeepValueOf'; import type IconAsset from '@src/types/utils/IconAsset'; import Button from './Button'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; -import type {AnchorAlignment} from './Popover/types'; import PopoverMenu from './PopoverMenu'; +type PaymentType = DeepValueOf; + type DropdownOption = { - value: string; + value: PaymentType; text: string; icon: IconAsset; iconWidth?: number; @@ -30,7 +33,7 @@ type ButtonWithDropdownMenuProps = { menuHeaderText?: string; /** Callback to execute when the main button is pressed */ - onPress: (event: GestureResponderEvent | KeyboardEvent | undefined, value: string) => void; + onPress: (event: GestureResponderEvent | KeyboardEvent | undefined, value: PaymentType) => void; /** Callback to execute when a dropdown option is selected */ onOptionSelected?: (option: DropdownOption) => void; @@ -59,6 +62,9 @@ type ButtonWithDropdownMenuProps = { /* ref for the button */ buttonRef: RefObject; + + /** The priority to assign the enter key event listener to buttons. 0 is the highest priority. */ + enterKeyEventListenerPriority?: number; }; function ButtonWithDropdownMenu({ @@ -76,6 +82,7 @@ function ButtonWithDropdownMenu({ onPress, options, onOptionSelected, + enterKeyEventListenerPriority = 0, }: ButtonWithDropdownMenuProps) { const theme = useTheme(); const styles = useThemeStyles(); @@ -126,6 +133,7 @@ function ButtonWithDropdownMenu({ large={isButtonSizeLarge} medium={!isButtonSizeLarge} innerStyles={[innerStyleDropButton]} + enterKeyEventListenerPriority={enterKeyEventListenerPriority} />