diff --git a/.eslintrc.js b/.eslintrc.js index 5f450f3ae6c2..cfbfdcc8fe91 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -109,7 +109,6 @@ module.exports = { 'plugin:prettier/recommended', ], plugins: ['@typescript-eslint', 'jsdoc', 'you-dont-need-lodash-underscore', 'react-native-a11y', 'react', 'testing-library', 'eslint-plugin-react-compiler', 'lodash', 'deprecation'], - ignorePatterns: ['lib/**'], parser: '@typescript-eslint/parser', parserOptions: { project: path.resolve(__dirname, './tsconfig.json'), diff --git a/.github/workflows/e2ePerformanceTests.yml b/.github/workflows/e2ePerformanceTests.yml index b48c7b2175eb..c92ab83d1178 100644 --- a/.github/workflows/e2ePerformanceTests.yml +++ b/.github/workflows/e2ePerformanceTests.yml @@ -35,8 +35,16 @@ jobs: - name: Determine "baseline ref" (prev merge commit) id: getBaselineRef run: | - previous_merge=$(git rev-list --merges HEAD~1 | head -n 1) - git checkout "$previous_merge" + # Get the name of the current branch + current_branch=$(git rev-parse --abbrev-ref HEAD) + + if [ "$current_branch" = "main" ]; then + # On the main branch, find the previous merge commit + previous_merge=$(git rev-list --merges HEAD~1 | head -n 1) + else + # On a feature branch, find the common ancestor of the current branch and main + previous_merge=$(git merge-base HEAD main) + fi echo "$previous_merge" echo "BASELINE_REF=$previous_merge" >> "$GITHUB_OUTPUT" diff --git a/.prettierignore b/.prettierignore index c4c88bd11d3e..b428978a1563 100644 --- a/.prettierignore +++ b/.prettierignore @@ -18,8 +18,6 @@ package-lock.json *.markdown # We need to modify the import here specifically, hence we disable prettier to get rid of the sorted imports src/libs/E2E/reactNativeLaunchingTest.ts -# Temporary while we keep react-compiler in our repo -lib/** # Automatically generated files src/libs/SearchParser/searchParser.js diff --git a/android/app/src/main/java/com/expensify/chat/MainApplication.kt b/android/app/src/main/java/com/expensify/chat/MainApplication.kt index f476ad89c5b4..942304c80445 100644 --- a/android/app/src/main/java/com/expensify/chat/MainApplication.kt +++ b/android/app/src/main/java/com/expensify/chat/MainApplication.kt @@ -64,7 +64,7 @@ class MainApplication : MultiDexApplication(), ReactApplication { SoLoader.init(this, /* native exopackage */false) if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { // If you opted-in for the New Architecture, we load the native entry point for this app. - load() + load(bridgelessEnabled = false) } if (BuildConfig.DEBUG) { FirebaseCrashlytics.getInstance().setCrashlyticsCollectionEnabled(false) diff --git a/babel.config.js b/babel.config.js index 663eb29d5d2f..3f0fff03736d 100644 --- a/babel.config.js +++ b/babel.config.js @@ -3,11 +3,14 @@ require('dotenv').config(); const IS_E2E_TESTING = process.env.E2E_TESTING === 'true'; const ReactCompilerConfig = { - runtimeModule: 'react-compiler-runtime', + target: '18', environment: { enableTreatRefLikeIdentifiersAsRefs: true, }, + // We exclude 'tests' directory from compilation, but still compile components imported in test files. + sources: (filename) => !filename.includes('tests/') && !filename.includes('node_modules/'), }; + /** * Setting targets to node 20 to reduce JS bundle size * It is also recommended by babel: @@ -52,6 +55,8 @@ const webpack = { const metro = { presets: [require('@react-native/babel-preset')], plugins: [ + ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! + // This is needed due to a react-native bug: https://github.com/facebook/react-native/issues/29084#issuecomment-1030732709 // It is included in metro-react-native-babel-preset but needs to be before plugin-proposal-class-properties or FlatList will break '@babel/plugin-transform-flow-strip-types', @@ -154,11 +159,5 @@ module.exports = (api) => { const runningIn = api.caller((args = {}) => args.name); console.debug(' - running in: ', runningIn); - // don't include react-compiler in jest, because otherwise tests will fail - if (runningIn !== 'babel-jest') { - // must run first! - metro.plugins.unshift(['babel-plugin-react-compiler', ReactCompilerConfig]); - } - return ['metro', 'babel-jest'].includes(runningIn) ? metro : webpack; }; diff --git a/docs/assets/images/ExpensifyHelp_OldDot_PayInvoice_1.png b/docs/assets/images/ExpensifyHelp_OldDot_PayInvoice_1.png new file mode 100644 index 000000000000..53c637736c95 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_OldDot_PayInvoice_1.png differ diff --git a/docs/assets/images/ExpensifyHelp_OldDot_PayInvoice_2.png b/docs/assets/images/ExpensifyHelp_OldDot_PayInvoice_2.png new file mode 100644 index 000000000000..92e607756de2 Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_OldDot_PayInvoice_2.png differ diff --git a/docs/redirects.csv b/docs/redirects.csv index a7d4d94adb5d..d3672618cfad 100644 --- a/docs/redirects.csv +++ b/docs/redirects.csv @@ -585,7 +585,8 @@ https://community.expensify.com/discussion/6699/faq-troubleshooting-known-bank-s https://community.expensify.com/discussion/4730/faq-expenses-are-exporting-to-the-wrong-accounts-whys-that,https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Company-Card-Settings https://community.expensify.com/discussion/9000/how-to-integrate-with-deel,https://help.expensify.com/articles/expensify-classic/connections/Deel https://community.expensify.com/categories/expensify-classroom,https://use.expensify.com -https://help.expensify.com/articles/new-expensify/billing-and-subscriptions/adding-payment-card-subscription-overview,https://help.expensify.com/articles/new-expensify/billing-and-subscriptions/add-a-payment-card-and-view-your-subscription +https://help.expensify.com/articles/new-expensify/billing-and-subscriptions/adding-payment-card-subscription-overview,https://help.expensify.com/articles/new-expensify/billing-and-subscriptions/Add-a-payment-card-and-view-your-subscription https://help.expensify.com/articles/expensify-classic/articles/expensify-classic/expenses/Send-Receive-for-Invoices,https://help.expensify.com/articles/expensify-classic/articles/expensify-classic/expenses/Send-and-Receive-Payment-for-Invoices.md https://help.expensify.com/articles/expensify-classic/articles/expensify-classic/expenses/Bulk-Upload-Multiple-Invoices,https://help.expensify.com/articles/expensify-classic/articles/expensify-classic/expenses/Add-Invoices-in-Bulk -https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Pay-Bills,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Create-and-Pay-Bills \ No newline at end of file +https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Pay-Bills,https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/payments/Create-and-Pay-Bills +https://help.expensify.com/articles/new-expensify/billing-and-subscriptions/add-a-payment-card-and-view-your-subscription,https://help.expensify.com/articles/new-expensify/billing-and-subscriptions/Add-a-payment-card-and-view-your-subscription diff --git a/lib/react-compiler-runtime/index.js b/lib/react-compiler-runtime/index.js deleted file mode 100644 index 54e88d2b703a..000000000000 --- a/lib/react-compiler-runtime/index.js +++ /dev/null @@ -1,21 +0,0 @@ -// lib/react-compiler-runtime.js -const $empty = Symbol.for("react.memo_cache_sentinel"); -const React = require('react'); -/** - * DANGER: this hook is NEVER meant to be called directly! - * - * Note that this is a temporary userspace implementation of this function - * from React 19. It is not as efficient and may invalidate more frequently - * than the official API. Better to upgrade to React 19 as soon as we can. - **/ -export function c(size) { - return React.useState(() => { - const $ = new Array(size); - for (let ii = 0; ii < size; ii++) { - $[ii] = $empty; - } - // @ts-ignore - $[$empty] = true; - return $; - })[0]; -} diff --git a/lib/react-compiler-runtime/package.json b/lib/react-compiler-runtime/package.json deleted file mode 100644 index 3a0323538b6e..000000000000 --- a/lib/react-compiler-runtime/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "react-compiler-runtime", - "version": "0.0.1", - "description": "Runtime for React Compiler", - "license": "MIT", - "main": "index.js", - "dependencies": { - "react": "18.3.1" - } -} diff --git a/package-lock.json b/package-lock.json index 02597aafd9fc..7202ef76ab66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -204,7 +204,7 @@ "babel-jest": "29.4.1", "babel-loader": "^9.1.3", "babel-plugin-module-resolver": "^5.0.0", - "babel-plugin-react-compiler": "0.0.0-experimental-334f00b-20240725", + "babel-plugin-react-compiler": "^19.0.0-beta-8a03594-20241020", "babel-plugin-react-native-web": "^0.18.7", "babel-plugin-transform-remove-console": "^6.9.4", "clean-webpack-plugin": "^4.0.0", @@ -225,7 +225,7 @@ "eslint-plugin-jest": "^28.6.0", "eslint-plugin-jsdoc": "^46.2.6", "eslint-plugin-lodash": "^7.4.0", - "eslint-plugin-react-compiler": "0.0.0-experimental-9ed098e-20240725", + "eslint-plugin-react-compiler": "^19.0.0-beta-8a03594-20241020", "eslint-plugin-react-native-a11y": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", "eslint-plugin-testing-library": "^6.2.2", @@ -248,8 +248,8 @@ "portfinder": "^1.0.28", "prettier": "^2.8.8", "pusher-js-mock": "^0.3.3", - "react-compiler-healthcheck": "^0.0.0-experimental-ab3118d-20240725", - "react-compiler-runtime": "file:./lib/react-compiler-runtime", + "react-compiler-healthcheck": "^19.0.0-beta-8a03594-20241020", + "react-compiler-runtime": "^19.0.0-beta-8a03594-20241020", "react-is": "^18.3.1", "react-native-clean-project": "^4.0.0-alpha4.0", "react-test-renderer": "18.3.1", @@ -279,14 +279,6 @@ "npm": "10.8.2" } }, - "lib/react-compiler-runtime": { - "version": "0.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "react": "18.3.1" - } - }, "node_modules/@actions/core": { "version": "1.10.0", "dev": true, @@ -18346,9 +18338,10 @@ } }, "node_modules/babel-plugin-react-compiler": { - "version": "0.0.0-experimental-334f00b-20240725", + "version": "19.0.0-beta-8a03594-20241020", + "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-19.0.0-beta-8a03594-20241020.tgz", + "integrity": "sha512-Wk0748DZzQEmjkEN4SbBujM5al4q5TfRBapA32ax0AID/Yek3emS+eyCvPvb4zPddYJTAF4LaJNLt8uHYfdKAQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/generator": "7.2.0", "@babel/types": "^7.19.0", @@ -23532,9 +23525,10 @@ } }, "node_modules/eslint-plugin-react-compiler": { - "version": "0.0.0-experimental-9ed098e-20240725", + "version": "19.0.0-beta-8a03594-20241020", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.0.0-beta-8a03594-20241020.tgz", + "integrity": "sha512-bYg1COih1s3r14IV/AKdQs/SN7CQmNI0ZaMtPdgZ6gp1S1Q/KGP9P43w7R6dHJ4wYpuMBvekNJHQdVu+x6UM+A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", @@ -34077,9 +34071,10 @@ } }, "node_modules/react-compiler-healthcheck": { - "version": "0.0.0-experimental-b130d5f-20240625", + "version": "19.0.0-beta-8a03594-20241020", + "resolved": "https://registry.npmjs.org/react-compiler-healthcheck/-/react-compiler-healthcheck-19.0.0-beta-8a03594-20241020.tgz", + "integrity": "sha512-wupgZ4fASQ+oRI88V6QIERKCHZUo6322LXlH8EotsWQDc8c4EXgPdkZHO/zH+zDh4Np4qZM36bFbZgHPXtI0FA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.24.4", "@babel/parser": "^7.24.4", @@ -34162,8 +34157,13 @@ } }, "node_modules/react-compiler-runtime": { - "resolved": "lib/react-compiler-runtime", - "link": true + "version": "19.0.0-beta-8a03594-20241020", + "resolved": "https://registry.npmjs.org/react-compiler-runtime/-/react-compiler-runtime-19.0.0-beta-8a03594-20241020.tgz", + "integrity": "sha512-YWl8SjxsWGU1dpxHvWS0vxTkpeLXTZ/Y7IVzwZGj6yAfXOEie1MduuAR0TFiGeV0RxFLp5jKUIWl+ZglN4dMQw==", + "dev": true, + "peerDependencies": { + "react": "^18.2.0 || ^19.0.0" + } }, "node_modules/react-content-loader": { "version": "7.0.0", diff --git a/package.json b/package.json index 6f63136e08ba..f0425a747967 100644 --- a/package.json +++ b/package.json @@ -260,7 +260,7 @@ "babel-jest": "29.4.1", "babel-loader": "^9.1.3", "babel-plugin-module-resolver": "^5.0.0", - "babel-plugin-react-compiler": "0.0.0-experimental-334f00b-20240725", + "babel-plugin-react-compiler": "^19.0.0-beta-8a03594-20241020", "babel-plugin-react-native-web": "^0.18.7", "babel-plugin-transform-remove-console": "^6.9.4", "clean-webpack-plugin": "^4.0.0", @@ -281,7 +281,7 @@ "eslint-plugin-jest": "^28.6.0", "eslint-plugin-jsdoc": "^46.2.6", "eslint-plugin-lodash": "^7.4.0", - "eslint-plugin-react-compiler": "0.0.0-experimental-9ed098e-20240725", + "eslint-plugin-react-compiler": "^19.0.0-beta-8a03594-20241020", "eslint-plugin-react-native-a11y": "^3.3.0", "eslint-plugin-storybook": "^0.8.0", "eslint-plugin-testing-library": "^6.2.2", @@ -304,8 +304,8 @@ "portfinder": "^1.0.28", "prettier": "^2.8.8", "pusher-js-mock": "^0.3.3", - "react-compiler-healthcheck": "^0.0.0-experimental-ab3118d-20240725", - "react-compiler-runtime": "file:./lib/react-compiler-runtime", + "react-compiler-healthcheck": "^19.0.0-beta-8a03594-20241020", + "react-compiler-runtime": "^19.0.0-beta-8a03594-20241020", "react-is": "^18.3.1", "react-native-clean-project": "^4.0.0-alpha4.0", "react-test-renderer": "18.3.1", diff --git a/patches/@react-native-firebase+app+12.9.3+002+bridgeless.patch b/patches/@react-native-firebase+app+12.9.3+002+bridgeless.patch index a085cdbcfbe2..54ae4d9a1c58 100644 --- a/patches/@react-native-firebase+app+12.9.3+002+bridgeless.patch +++ b/patches/@react-native-firebase+app+12.9.3+002+bridgeless.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/@react-native-firebase/app/lib/internal/registry/nativeModule.js b/node_modules/@react-native-firebase/app/lib/internal/registry/nativeModule.js -index 03f001c..23d467d 100644 +index 03f001c..358c795 100644 --- a/node_modules/@react-native-firebase/app/lib/internal/registry/nativeModule.js +++ b/node_modules/@react-native-firebase/app/lib/internal/registry/nativeModule.js @@ -65,7 +65,7 @@ function nativeModuleWrapped(namespace, NativeModule, argToPrepend) { @@ -7,7 +7,7 @@ index 03f001c..23d467d 100644 } - const properties = Object.keys(NativeModule); -+ const properties = Object.keys(Object.getPrototypeOf(NativeModule)); ++ const properties = [...Object.keys(Object.getPrototypeOf(NativeModule)), ...Object.keys(NativeModule)]; for (let i = 0, len = properties.length; i < len; i++) { const property = properties[i]; diff --git a/patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+001+initial.patch b/patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+001+initial.patch similarity index 66% rename from patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+001+initial.patch rename to patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+001+initial.patch index d7c02701a636..03b386587338 100644 --- a/patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+001+initial.patch +++ b/patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+001+initial.patch @@ -1,8 +1,8 @@ diff --git a/node_modules/react-compiler-healthcheck/dist/index.js b/node_modules/react-compiler-healthcheck/dist/index.js -index b427385..4bf23db 100755 +index 5a4060d..460339b 100755 --- a/node_modules/react-compiler-healthcheck/dist/index.js +++ b/node_modules/react-compiler-healthcheck/dist/index.js -@@ -69154,7 +69154,7 @@ var reactCompilerCheck = { +@@ -56969,7 +56969,7 @@ var reactCompilerCheck = { compile(source, path); } }, @@ -11,11 +11,11 @@ index b427385..4bf23db 100755 const totalComponents = SucessfulCompilation.length + countUniqueLocInEvents(OtherFailures) + -@@ -69164,6 +69164,50 @@ var reactCompilerCheck = { +@@ -56979,6 +56979,50 @@ var reactCompilerCheck = { `Successfully compiled ${SucessfulCompilation.length} out of ${totalComponents} components.` ) ); -+ ++ + if (verbose) { + for (const compilation of [...SucessfulCompilation, ...ActionableFailures, ...OtherFailures]) { + const filename = compilation.fnLoc?.filename; @@ -38,33 +38,33 @@ index b427385..4bf23db 100755 + if (compilation.kind === "CompileError") { + const { reason, severity, loc } = compilation.detail; + -+ const lnNo = loc.start?.line; -+ const colNo = loc.start?.column; ++ const lnNo = loc.start?.line; ++ const colNo = loc.start?.column; + -+ const isTodo = severity === ErrorSeverity.Todo; ++ const isTodo = severity === ErrorSeverity.Todo; + -+ console.log( -+ chalk[isTodo ? 'yellow' : 'red']( -+ `Failed to compile ${ -+ filename -+ }${ -+ lnNo !== undefined ? `:${lnNo}${ -+ colNo !== undefined ? `:${colNo}` : "" -+ }.` : "" -+ }` -+ ), -+ chalk[isTodo ? 'yellow' : 'red'](reason? `Reason: ${reason}` : "") -+ ); -+ console.log("\n"); ++ console.log( ++ chalk[isTodo ? 'yellow' : 'red']( ++ `Failed to compile ${ ++ filename ++ }${ ++ lnNo !== undefined ? `:${lnNo}${ ++ colNo !== undefined ? `:${colNo}` : "" ++ }.` : "" ++ }` ++ ), ++ chalk[isTodo ? 'yellow' : 'red'](reason? `Reason: ${reason}` : "") ++ ); ++ console.log("\n"); + } + } + } }, }; const JsFileExtensionRE = /(js|ts|jsx|tsx)$/; -@@ -69200,9 +69244,16 @@ function main() { - type: "string", - default: "**/+(*.{js,mjs,jsx,ts,tsx}|package.json)", +@@ -57015,9 +57059,16 @@ function main() { + type: 'string', + default: '**/+(*.{js,mjs,jsx,ts,tsx}|package.json)', }) + .option('verbose', { + description: 'run with verbose logging', @@ -73,13 +73,13 @@ index b427385..4bf23db 100755 + alias: 'v', + }) .parseSync(); - const spinner = ora("Checking").start(); + const spinner = ora('Checking').start(); let src = argv.src; + let verbose = argv.verbose; const globOptions = { onlyFiles: true, ignore: [ -@@ -69222,7 +69273,7 @@ function main() { +@@ -57037,7 +57088,7 @@ function main() { libraryCompatCheck.run(source, path); } spinner.stop(); diff --git a/patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+002+enable-ref-identifiers.patch b/patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+002+enable-ref-identifiers.patch similarity index 65% rename from patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+002+enable-ref-identifiers.patch rename to patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+002+enable-ref-identifiers.patch index 6caa4ad4c373..8ae46e379619 100644 --- a/patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+002+enable-ref-identifiers.patch +++ b/patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+002+enable-ref-identifiers.patch @@ -1,28 +1,28 @@ diff --git a/node_modules/react-compiler-healthcheck/dist/index.js b/node_modules/react-compiler-healthcheck/dist/index.js -index 4bf23db..fa2ab22 100755 +index 460339b..17b0f96 100755 --- a/node_modules/react-compiler-healthcheck/dist/index.js +++ b/node_modules/react-compiler-healthcheck/dist/index.js -@@ -69088,6 +69088,9 @@ const COMPILER_OPTIONS = { - compilationMode: "infer", - panicThreshold: "critical_errors", - logger: logger, +@@ -56902,6 +56902,9 @@ const COMPILER_OPTIONS = { + noEmit: true, + compilationMode: 'infer', + panicThreshold: 'critical_errors', + environment: { + enableTreatRefLikeIdentifiersAsRefs: true, + }, + logger: logger, }; function isActionableDiagnostic(detail) { - switch (detail.severity) { diff --git a/node_modules/react-compiler-healthcheck/src/checks/reactCompiler.ts b/node_modules/react-compiler-healthcheck/src/checks/reactCompiler.ts -index 09c9b9b..d2418e0 100644 +index 3094548..fd05b76 100644 --- a/node_modules/react-compiler-healthcheck/src/checks/reactCompiler.ts +++ b/node_modules/react-compiler-healthcheck/src/checks/reactCompiler.ts -@@ -51,6 +51,9 @@ const COMPILER_OPTIONS: Partial = { - compilationMode: "infer", - panicThreshold: "critical_errors", - logger, +@@ -50,6 +50,9 @@ const COMPILER_OPTIONS: Partial = { + noEmit: true, + compilationMode: 'infer', + panicThreshold: 'critical_errors', + environment: { + enableTreatRefLikeIdentifiersAsRefs: true, + }, + logger, }; - function isActionableDiagnostic(detail: CompilerErrorDetailOptions) { diff --git a/patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+003+json.patch b/patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+003+json.patch similarity index 88% rename from patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+003+json.patch rename to patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+003+json.patch index a3de7a365889..246351351195 100644 --- a/patches/react-compiler-healthcheck+0.0.0-experimental-b130d5f-20240625+003+json.patch +++ b/patches/react-compiler-healthcheck+19.0.0-beta-8a03594-20241020+003+json.patch @@ -1,8 +1,8 @@ diff --git a/node_modules/react-compiler-healthcheck/dist/index.js b/node_modules/react-compiler-healthcheck/dist/index.js -index fa2ab22..93be1fb 100755 +index 17b0f96..e386e34 100755 --- a/node_modules/react-compiler-healthcheck/dist/index.js +++ b/node_modules/react-compiler-healthcheck/dist/index.js -@@ -69157,16 +69157,28 @@ var reactCompilerCheck = { +@@ -56972,16 +56972,28 @@ var reactCompilerCheck = { compile(source, path); } }, @@ -24,7 +24,7 @@ index fa2ab22..93be1fb 100755 + ) + ); + } -+ ++ + if (json) { + const extractFileName = (output) => output.fnLoc.filename; + const successfulFiles = SucessfulCompilation.map(extractFileName); @@ -34,10 +34,10 @@ index fa2ab22..93be1fb 100755 + failure: unsuccessfulFiles, + })); + } - + if (verbose) { for (const compilation of [...SucessfulCompilation, ...ActionableFailures, ...OtherFailures]) { -@@ -69253,10 +69265,17 @@ function main() { +@@ -57068,10 +57080,17 @@ function main() { default: false, alias: 'v', }) @@ -48,14 +48,14 @@ index fa2ab22..93be1fb 100755 + alias: 'j', + }) .parseSync(); - const spinner = ora("Checking").start(); + const spinner = ora('Checking').start(); let src = argv.src; let verbose = argv.verbose; + let json = argv.json; const globOptions = { onlyFiles: true, ignore: [ -@@ -69276,9 +69295,12 @@ function main() { +@@ -57091,9 +57110,11 @@ function main() { libraryCompatCheck.run(source, path); } spinner.stop(); @@ -63,7 +63,6 @@ index fa2ab22..93be1fb 100755 - strictModeCheck.report(); - libraryCompatCheck.report(); + reactCompilerCheck.report(verbose, json); -+ // using json option we only want to get list of files + if (!json) { + strictModeCheck.report(); + libraryCompatCheck.report(); diff --git a/src/CONST.ts b/src/CONST.ts index d5680ce34b6f..dd048f95d374 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -4840,10 +4840,11 @@ const CONST = { '\n' + 'Here’s how to request money:\n' + '\n' + - '1. Click the green *+* button.\n' + - '2. Choose *Split expense*.\n' + - '3. Scan a receipt or enter an amount.\n' + - '4. Add your friend(s) to the request.\n' + + '1. Hit the green *+* button.\n' + + '2. Choose *Start chat*.\n' + + '3. Enter any email, SMS, or name of who you want to split with.\n' + + '4. From within the chat, hit the *+* button on the message bar, and hit *Split expense*.\n' + + '5. Create the expense by selecting Manual, Scan or Distance.\n' + '\n' + 'Feel free to add more details if you want, or just send it off. Let’s get you paid back!', }, diff --git a/src/components/AttachmentPicker/index.native.tsx b/src/components/AttachmentPicker/index.native.tsx index 975ea6c548c0..d3a51c7fc0f0 100644 --- a/src/components/AttachmentPicker/index.native.tsx +++ b/src/components/AttachmentPicker/index.native.tsx @@ -417,6 +417,7 @@ function AttachmentPicker({ }} isVisible={isVisible} anchorRef={popoverRef} + // eslint-disable-next-line react-compiler/react-compiler onModalHide={onModalHide.current} > @@ -431,6 +432,7 @@ function AttachmentPicker({ ))} + {/* eslint-disable-next-line react-compiler/react-compiler */} {renderChildren()} ); diff --git a/src/components/AttachmentPicker/index.tsx b/src/components/AttachmentPicker/index.tsx index c4979f544080..f3c880fcb835 100644 --- a/src/components/AttachmentPicker/index.tsx +++ b/src/components/AttachmentPicker/index.tsx @@ -98,6 +98,7 @@ function AttachmentPicker({children, type = CONST.ATTACHMENT_PICKER_TYPE.FILE, a }} accept={acceptedFileTypes ? getAcceptableFileTypesFromAList(acceptedFileTypes) : getAcceptableFileTypes(type)} /> + {/* eslint-disable-next-line react-compiler/react-compiler */} {children({ openPicker: ({onPicked: newOnPicked, onCanceled: newOnCanceled = () => {}}) => { onPicked.current = newOnPicked; diff --git a/src/components/Attachments/AttachmentCarousel/index.tsx b/src/components/Attachments/AttachmentCarousel/index.tsx index a1408aaf400e..d9c4f7e93fbe 100644 --- a/src/components/Attachments/AttachmentCarousel/index.tsx +++ b/src/components/Attachments/AttachmentCarousel/index.tsx @@ -255,6 +255,7 @@ function AttachmentCarousel({report, source, onNavigate, setDownloadButtonVisibi scrollTo(scrollRef, newIndex * cellWidth, 0, true); }) + // eslint-disable-next-line react-compiler/react-compiler .withRef(pagerRef as MutableRefObject), [attachments.length, canUseTouchScreen, cellWidth, page, scale, scrollRef], ); diff --git a/src/components/AvatarCropModal/AvatarCropModal.tsx b/src/components/AvatarCropModal/AvatarCropModal.tsx index 1a606b35f6d2..dca0d08d11d5 100644 --- a/src/components/AvatarCropModal/AvatarCropModal.tsx +++ b/src/components/AvatarCropModal/AvatarCropModal.tsx @@ -336,6 +336,7 @@ function AvatarCropModal({imageUri = '', imageName = '', imageType = '', onClose } const newSliderValue = clamp(locationX, [0, sliderContainerSize]); const newScale = newScaleValue(newSliderValue, sliderContainerSize); + // eslint-disable-next-line react-compiler/react-compiler translateSlider.value = newSliderValue; const differential = newScale / scale.value; scale.value = newScale; diff --git a/src/components/ButtonWithDropdownMenu/index.tsx b/src/components/ButtonWithDropdownMenu/index.tsx index e1d7beb850d0..c44054c15445 100644 --- a/src/components/ButtonWithDropdownMenu/index.tsx +++ b/src/components/ButtonWithDropdownMenu/index.tsx @@ -53,6 +53,7 @@ function ButtonWithDropdownMenu({ const [popoverAnchorPosition, setPopoverAnchorPosition] = useState(null); const {windowWidth, windowHeight} = useWindowDimensions(); const dropdownAnchor = useRef(null); + // eslint-disable-next-line react-compiler/react-compiler const dropdownButtonRef = isSplitButton ? buttonRef : mergeRefs(buttonRef, dropdownAnchor); const selectedItem = options.at(selectedItemIndex) ?? options.at(0); const innerStyleDropButton = StyleUtils.getDropDownButtonHeight(buttonSize); @@ -200,6 +201,7 @@ function ButtonWithDropdownMenu({ onItemSelected={() => setIsMenuVisible(false)} anchorPosition={shouldUseStyleUtilityForAnchorPosition ? styles.popoverButtonDropdownMenuOffset(windowWidth) : popoverAnchorPosition} shouldShowSelectedItemCheck={shouldShowSelectedItemCheck} + // eslint-disable-next-line react-compiler/react-compiler anchorRef={nullCheckRef(dropdownAnchor)} withoutOverlay anchorAlignment={anchorAlignment} diff --git a/src/components/ButtonWithDropdownMenu/types.ts b/src/components/ButtonWithDropdownMenu/types.ts index da6b3d93433d..766c0df950b4 100644 --- a/src/components/ButtonWithDropdownMenu/types.ts +++ b/src/components/ButtonWithDropdownMenu/types.ts @@ -25,6 +25,7 @@ type DropdownOption = { iconWidth?: number; iconHeight?: number; iconDescription?: string; + additionalIconStyles?: StyleProp; onSelected?: () => void; disabled?: boolean; iconFill?: string; diff --git a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx index 86edbb3b4c5e..acc1a7f40b47 100644 --- a/src/components/DisplayNames/DisplayNamesWithTooltip.tsx +++ b/src/components/DisplayNames/DisplayNamesWithTooltip.tsx @@ -15,6 +15,7 @@ function DisplayNamesWithToolTip({shouldUseFullTitle, fullTitle, displayNamesWit const styles = useThemeStyles(); const containerRef = useRef(null); const childRefs = useRef([]); + // eslint-disable-next-line react-compiler/react-compiler const isEllipsisActive = !!containerRef.current?.offsetWidth && !!containerRef.current?.scrollWidth && containerRef.current.offsetWidth < containerRef.current.scrollWidth; /** diff --git a/src/components/DragAndDrop/NoDropZone/index.tsx b/src/components/DragAndDrop/NoDropZone/index.tsx index 3438bfff7c05..b55db0e6c212 100644 --- a/src/components/DragAndDrop/NoDropZone/index.tsx +++ b/src/components/DragAndDrop/NoDropZone/index.tsx @@ -11,12 +11,14 @@ function NoDropZone({children}: NoDropZoneProps) { const noDropZone = useRef(null); useDragAndDrop({ + // eslint-disable-next-line react-compiler/react-compiler dropZone: htmlDivElementRef(noDropZone), shouldAllowDrop: false, }); return ( diff --git a/src/components/DragAndDrop/Provider/index.tsx b/src/components/DragAndDrop/Provider/index.tsx index 1011fa161312..a403c7ecca0d 100644 --- a/src/components/DragAndDrop/Provider/index.tsx +++ b/src/components/DragAndDrop/Provider/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-compiler/react-compiler */ import {PortalHost} from '@gorhom/portal'; import {Str} from 'expensify-common'; import React, {useCallback, useEffect, useMemo, useRef} from 'react'; diff --git a/src/components/DraggableList/useDraggableInPortal.ts b/src/components/DraggableList/useDraggableInPortal.ts index 3b4610ce1e5e..e4e01ee4b133 100644 --- a/src/components/DraggableList/useDraggableInPortal.ts +++ b/src/components/DraggableList/useDraggableInPortal.ts @@ -7,6 +7,7 @@ type DraggableInPortal = { }; export default function useDraggableInPortal({shouldUsePortal}: DraggableInPortal): (render: DraggableChildrenFn) => DraggableChildrenFn { + // eslint-disable-next-line react-compiler/react-compiler const element = useRef(document.createElement('div')).current; useEffect(() => { diff --git a/src/components/EmojiPicker/EmojiPicker.tsx b/src/components/EmojiPicker/EmojiPicker.tsx index 706265f2e11a..79af5bc0a4f2 100644 --- a/src/components/EmojiPicker/EmojiPicker.tsx +++ b/src/components/EmojiPicker/EmojiPicker.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-compiler/react-compiler */ import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; import type {ForwardedRef, RefObject} from 'react'; import {Dimensions, View} from 'react-native'; @@ -117,7 +118,7 @@ function EmojiPicker({viewportOffsetTop}: EmojiPickerProps, ref: ForwardedRef open(onPicked, newOnCanceled), }); + // eslint-disable-next-line react-compiler/react-compiler return <>{renderChildren()}; } diff --git a/src/components/FilePicker/index.tsx b/src/components/FilePicker/index.tsx index 2514a16053bd..3d4242d22420 100644 --- a/src/components/FilePicker/index.tsx +++ b/src/components/FilePicker/index.tsx @@ -65,6 +65,7 @@ function FilePicker({children, acceptableFileTypes = ''}: FilePickerProps): Reac }} accept={acceptableFileTypes} /> + {/* eslint-disable-next-line react-compiler/react-compiler */} {children({ openPicker: ({onPicked: newOnPicked, onCanceled: newOnCanceled = () => {}}) => { onPicked.current = newOnPicked; diff --git a/src/components/FlatList/index.tsx b/src/components/FlatList/index.tsx index 9bca23efb384..be0227375470 100644 --- a/src/components/FlatList/index.tsx +++ b/src/components/FlatList/index.tsx @@ -50,6 +50,7 @@ function MVCPFlatList({maintainVisibleContentPosition, horizontal = false const lastScrollOffsetRef = useRef(0); const isListRenderedRef = useRef(false); const mvcpAutoscrollToTopThresholdRef = useRef(mvcpAutoscrollToTopThreshold); + // eslint-disable-next-line react-compiler/react-compiler mvcpAutoscrollToTopThresholdRef.current = mvcpAutoscrollToTopThreshold; const getScrollOffset = useCallback((): number => { diff --git a/src/components/Form/InputWrapper.tsx b/src/components/Form/InputWrapper.tsx index f54009852b22..a01c1ca3c136 100644 --- a/src/components/Form/InputWrapper.tsx +++ b/src/components/Form/InputWrapper.tsx @@ -76,6 +76,7 @@ function InputWrapper(p const {registerInput} = useContext(FormContext); const {shouldSetTouchedOnBlurOnly, blurOnSubmit, shouldSubmitForm} = computeComponentSpecificRegistrationParams(props as InputComponentBaseProps); + // eslint-disable-next-line react-compiler/react-compiler const {key, ...registerInputProps} = registerInput(inputID, shouldSubmitForm, {ref, valueType, ...rest, shouldSetTouchedOnBlurOnly, blurOnSubmit}); return ( diff --git a/src/components/FormElement/index.tsx b/src/components/FormElement/index.tsx index 9a344eb3c39c..a4b864d69466 100644 --- a/src/components/FormElement/index.tsx +++ b/src/components/FormElement/index.tsx @@ -13,6 +13,7 @@ const preventFormDefault = (event: SubmitEvent) => { function FormElement(props: ViewProps, outerRef: ForwardedRef) { const formRef = useRef(null); + // eslint-disable-next-line react-compiler/react-compiler const mergedRef = mergeRefs(formRef, outerRef); useEffect(() => { diff --git a/src/components/Hoverable/ActiveHoverable.tsx b/src/components/Hoverable/ActiveHoverable.tsx index fd3d4f3d19e8..9bc0e846aaf1 100644 --- a/src/components/Hoverable/ActiveHoverable.tsx +++ b/src/components/Hoverable/ActiveHoverable.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-compiler/react-compiler */ import type {Ref} from 'react'; import {cloneElement, forwardRef, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {DeviceEventEmitter} from 'react-native'; diff --git a/src/components/Hoverable/index.tsx b/src/components/Hoverable/index.tsx index e3357fd963c4..3ff28a8da451 100644 --- a/src/components/Hoverable/index.tsx +++ b/src/components/Hoverable/index.tsx @@ -16,6 +16,7 @@ function Hoverable({isDisabled, ...props}: HoverableProps, ref: Ref // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing if (isDisabled || !hasHoverSupport()) { const child = getReturnValue(props.children, false); + // eslint-disable-next-line react-compiler/react-compiler return cloneElement(child, {ref: mergeRefs(ref, child.ref)}); } diff --git a/src/components/ImageView/index.tsx b/src/components/ImageView/index.tsx index e12be53d01ae..266ed2eed16a 100644 --- a/src/components/ImageView/index.tsx +++ b/src/components/ImageView/index.tsx @@ -210,6 +210,7 @@ function ImageView({isAuthTokenRequired = false, url, fileName, onError}: ImageV } return ( {translate('spreadsheet.upload')} diff --git a/src/components/KYCWall/BaseKYCWall.tsx b/src/components/KYCWall/BaseKYCWall.tsx index 7d1e6614c716..b846449faafd 100644 --- a/src/components/KYCWall/BaseKYCWall.tsx +++ b/src/components/KYCWall/BaseKYCWall.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-compiler/react-compiler */ import React, {useCallback, useEffect, useRef, useState} from 'react'; import {Dimensions} from 'react-native'; import type {EmitterSubscription, GestureResponderEvent, View} from 'react-native'; diff --git a/src/components/LHNOptionsList/OptionRowLHNData.tsx b/src/components/LHNOptionsList/OptionRowLHNData.tsx index 8253a1708c81..3c40210a5d99 100644 --- a/src/components/LHNOptionsList/OptionRowLHNData.tsx +++ b/src/components/LHNOptionsList/OptionRowLHNData.tsx @@ -54,10 +54,13 @@ function OptionRowLHNData({ transactionViolations, invoiceReceiverPolicy, }); + // eslint-disable-next-line react-compiler/react-compiler if (deepEqual(item, optionItemRef.current)) { + // eslint-disable-next-line react-compiler/react-compiler return optionItemRef.current; } + // eslint-disable-next-line react-compiler/react-compiler optionItemRef.current = item; return item; diff --git a/src/components/MagicCodeInput.tsx b/src/components/MagicCodeInput.tsx index ce4f3380a9b7..ff2db66dbc4a 100644 --- a/src/components/MagicCodeInput.tsx +++ b/src/components/MagicCodeInput.tsx @@ -212,6 +212,7 @@ function MagicCodeInput( */ const tapGesture = Gesture.Tap() .runOnJS(true) + // eslint-disable-next-line react-compiler/react-compiler .onBegin((event) => { const index = Math.floor(event.x / (inputWidth.current / maxLength)); shouldFocusLast.current = false; diff --git a/src/components/MenuItem.tsx b/src/components/MenuItem.tsx index 526a090afb73..a40fd925cd2e 100644 --- a/src/components/MenuItem.tsx +++ b/src/components/MenuItem.tsx @@ -114,6 +114,9 @@ type MenuItemBaseProps = { /** Any additional styles to pass to the icon container. */ iconStyles?: StyleProp; + /** Additional styles to pass to the icon itself */ + additionalIconStyles?: StyleProp; + /** A fallback avatar icon to display when there is an error on loading avatar from remote URL. */ fallbackIcon?: IconAsset; @@ -433,6 +436,7 @@ function MenuItem( tooltipShiftHorizontal = 0, tooltipShiftVertical = 0, renderTooltipContent, + additionalIconStyles, shouldShowSelectedItemCheck = false, onHideTooltip, shouldIconUseAutoWidthStyle = false, @@ -663,6 +667,7 @@ function MenuItem( isPaneMenu, ) } + additionalStyles={additionalIconStyles} /> ) : ( ({options, initializeOptions, areOptionsInitialized: areOptionsInitialized.current}), [options, initializeOptions])}> {children} diff --git a/src/components/PopoverProvider/index.tsx b/src/components/PopoverProvider/index.tsx index 82f3c6c7d61a..b59d1604a5aa 100644 --- a/src/components/PopoverProvider/index.tsx +++ b/src/components/PopoverProvider/index.tsx @@ -117,6 +117,7 @@ function PopoverContextProvider(props: PopoverContextProps) { () => ({ onOpen, close: closePopover, + // eslint-disable-next-line react-compiler/react-compiler popover: activePopoverRef.current, isOpen, }), diff --git a/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx b/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx index 84a595a7bf05..1765560eaae3 100644 --- a/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx +++ b/src/components/Pressable/GenericPressable/implementation/BaseGenericPressable.tsx @@ -148,6 +148,7 @@ function GenericPressable( onLayout={shouldUseAutoHitSlop ? onLayout : undefined} ref={ref as ForwardedRef} disabled={fullDisabled} + // eslint-disable-next-line react-compiler/react-compiler onPress={!isDisabled ? singleExecution(onPressHandler) : undefined} onLongPress={!isDisabled && onLongPress ? onLongPressHandler : undefined} onKeyDown={!isDisabled ? onKeyDown : undefined} diff --git a/src/components/Reactions/ReportActionItemEmojiReactions.tsx b/src/components/Reactions/ReportActionItemEmojiReactions.tsx index 943158607db4..bc5f48f9001c 100644 --- a/src/components/Reactions/ReportActionItemEmojiReactions.tsx +++ b/src/components/Reactions/ReportActionItemEmojiReactions.tsx @@ -104,6 +104,7 @@ function ReportActionItemEmojiReactions({ if (reactionCount === 0) { return null; } + // eslint-disable-next-line react-compiler/react-compiler totalReactionCount += reactionCount; const onPress = () => { diff --git a/src/components/ReportActionItem/ExportWithDropdownMenu.tsx b/src/components/ReportActionItem/ExportWithDropdownMenu.tsx index 2f96b9d7dfaf..50e753b25755 100644 --- a/src/components/ReportActionItem/ExportWithDropdownMenu.tsx +++ b/src/components/ReportActionItem/ExportWithDropdownMenu.tsx @@ -12,6 +12,7 @@ import * as ReportActions from '@libs/actions/Report'; import * as PolicyUtils from '@libs/PolicyUtils'; import * as ReportUtils from '@libs/ReportUtils'; import type {ExportType} from '@pages/home/report/ReportDetailsExportPage'; +import variables from '@styles/variables'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {Policy, Report} from '@src/types/onyx'; @@ -55,6 +56,9 @@ function ExportWithDropdownMenu({ icon: iconToDisplay, disabled: !canBeExported, displayInDefaultIconColor: true, + iconWidth: variables.iconSizeMenuItem, + iconHeight: variables.iconSizeMenuItem, + additionalIconStyles: styles.integrationIcon, }; const options = [ { diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index 152a14fc3eb7..4a7aab4ad299 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -162,6 +162,7 @@ function ScreenWrapper( const isKeyboardShownRef = useRef(false); + // eslint-disable-next-line react-compiler/react-compiler isKeyboardShownRef.current = keyboardState?.isKeyboardShown ?? false; const panResponder = useRef( diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index 5ff0882ea026..9238488361b0 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -1,6 +1,6 @@ import {useIsFocused, useNavigation} from '@react-navigation/native'; import type {StackNavigationProp} from '@react-navigation/stack'; -import React, {useCallback, useEffect, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {View} from 'react-native'; import type {NativeScrollEvent, NativeSyntheticEvent, StyleProp, ViewStyle} from 'react-native'; import type {OnyxEntry} from 'react-native-onyx'; @@ -172,10 +172,13 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr }); // save last non-empty search results to avoid ugly flash of loading screen when hash changes and onyx returns empty data + // eslint-disable-next-line react-compiler/react-compiler if (currentSearchResults?.data && currentSearchResults !== lastSearchResultsRef.current) { + // eslint-disable-next-line react-compiler/react-compiler lastSearchResultsRef.current = currentSearchResults; } + // eslint-disable-next-line react-compiler/react-compiler const searchResults = currentSearchResults?.data ? currentSearchResults : lastSearchResultsRef.current; const {newSearchResultKey, handleSelectionListScroll} = useSearchHighlightAndScroll({ @@ -193,7 +196,13 @@ function Search({queryJSON, onSearchListScroll, contentContainerStyle}: SearchPr const shouldShowLoadingMoreItems = !shouldShowLoadingState && searchResults?.search?.isLoading && searchResults?.search?.offset > 0; const isSearchResultsEmpty = !searchResults?.data || SearchUIUtils.isSearchResultsEmpty(searchResults); const prevIsSearchResultEmpty = usePrevious(isSearchResultsEmpty); - const data = searchResults === undefined ? [] : SearchUIUtils.getSections(type, status, searchResults.data, searchResults.search); + + const data = useMemo(() => { + if (searchResults === undefined) { + return []; + } + return SearchUIUtils.getSections(type, status, searchResults.data, searchResults.search); + }, [searchResults, status, type]); useEffect(() => { /** We only want to display the skeleton for the status filters the first time we load them for a specific data type */ diff --git a/src/components/Search/types.ts b/src/components/Search/types.ts index 4f96090be9d0..5db88ae47e8d 100644 --- a/src/components/Search/types.ts +++ b/src/components/Search/types.ts @@ -58,9 +58,10 @@ type QueryFilter = { type AdvancedFiltersKeys = ValueOf; -type QueryFilters = { - [K in AdvancedFiltersKeys]?: QueryFilter[]; -}; +type QueryFilters = Array<{ + key: AdvancedFiltersKeys; + filters: QueryFilter[]; +}>; type SearchQueryString = string; diff --git a/src/components/SwipeableView/index.native.tsx b/src/components/SwipeableView/index.native.tsx index e5b6d371e606..4376585c6f0a 100644 --- a/src/components/SwipeableView/index.native.tsx +++ b/src/components/SwipeableView/index.native.tsx @@ -7,6 +7,7 @@ function SwipeableView({children, onSwipeDown}: SwipeableViewProps) { const minimumPixelDistance = CONST.COMPOSER_MAX_HEIGHT; const oldYRef = useRef(0); const panResponder = useRef( + // eslint-disable-next-line react-compiler/react-compiler PanResponder.create({ // The PanResponder gets focus only when the y-axis movement is over minimumPixelDistance & swipe direction is downwards onMoveShouldSetPanResponderCapture: (_event, gestureState) => { @@ -22,10 +23,8 @@ function SwipeableView({children, onSwipeDown}: SwipeableViewProps) { }), ).current; - return ( - // eslint-disable-next-line react/jsx-props-no-spreading - {children} - ); + // eslint-disable-next-line react/jsx-props-no-spreading, react-compiler/react-compiler + return {children}; } SwipeableView.displayName = 'SwipeableView'; diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx index 1ddc65bbd0fc..d2b3f2c3a4ac 100644 --- a/src/components/Switch.tsx +++ b/src/components/Switch.tsx @@ -69,6 +69,7 @@ function Switch({isOn, onToggle, accessibilityLabel, disabled, showLockIcon, dis hoverDimmingValue={1} pressDimmingValue={0.8} > + {/* eslint-disable-next-line react-compiler/react-compiler */} {(!!disabled || !!showLockIcon) && ( StyleUtils.getTooltipStyles({ + // eslint-disable-next-line react-compiler/react-compiler tooltip: rootWrapper.current, currentSize: animation, windowWidth, diff --git a/src/components/Tooltip/BaseGenericTooltip/index.tsx b/src/components/Tooltip/BaseGenericTooltip/index.tsx index 4477c991e3ac..28f2458699b7 100644 --- a/src/components/Tooltip/BaseGenericTooltip/index.tsx +++ b/src/components/Tooltip/BaseGenericTooltip/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-compiler/react-compiler */ import React, {useLayoutEffect, useMemo, useRef, useState} from 'react'; import ReactDOM from 'react-dom'; import {Animated, View} from 'react-native'; diff --git a/src/components/Tooltip/GenericTooltip.tsx b/src/components/Tooltip/GenericTooltip.tsx index a59819a77f6c..7309359b8e0c 100644 --- a/src/components/Tooltip/GenericTooltip.tsx +++ b/src/components/Tooltip/GenericTooltip.tsx @@ -157,6 +157,7 @@ function GenericTooltip({ // Skip the tooltip and return the children if the text is empty, we don't have a render function. if (StringUtils.isEmptyString(text) && renderTooltipContent == null) { + // eslint-disable-next-line react-compiler/react-compiler return children({isVisible, showTooltip, hideTooltip, updateTargetBounds}); } @@ -164,6 +165,7 @@ function GenericTooltip({ <> {isRendered && ( )} - + {/* eslint-disable-next-line react-compiler/react-compiler */} {children({isVisible, showTooltip, hideTooltip, updateTargetBounds})} ); diff --git a/src/components/Tooltip/PopoverAnchorTooltip.tsx b/src/components/Tooltip/PopoverAnchorTooltip.tsx index 5eb1f45dafcc..1af0f01cf957 100644 --- a/src/components/Tooltip/PopoverAnchorTooltip.tsx +++ b/src/components/Tooltip/PopoverAnchorTooltip.tsx @@ -9,7 +9,7 @@ function PopoverAnchorTooltip({shouldRender = true, children, ...props}: Tooltip const tooltipRef = useRef(null); const isPopoverRelatedToTooltipOpen = useMemo(() => { - // eslint-disable-next-line @typescript-eslint/dot-notation + // eslint-disable-next-line @typescript-eslint/dot-notation, react-compiler/react-compiler const tooltipNode = (tooltipRef.current?.['_childNode'] as Node | undefined) ?? null; if ( diff --git a/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx b/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx index 966f49e45a93..42373da91789 100644 --- a/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx +++ b/src/components/VideoPlayerContexts/VideoPopoverMenuContext.tsx @@ -43,6 +43,7 @@ function VideoPopoverMenuContextProvider({children}: ChildrenProps) { const items: PopoverMenuItem[] = []; if (!isOffline && !isLocalFile) { + // eslint-disable-next-line react-compiler/react-compiler items.push({ icon: Expensicons.Download, text: translate('common.download'), diff --git a/src/hooks/useCancellationType.ts b/src/hooks/useCancellationType.ts index bc34f5feea6f..2a77bfd8ddc1 100644 --- a/src/hooks/useCancellationType.ts +++ b/src/hooks/useCancellationType.ts @@ -21,6 +21,7 @@ function useCancellationType(): CancellationType | undefined { } // There are no new items in the cancellation details NVP + // eslint-disable-next-line react-compiler/react-compiler if (previousCancellationDetails.current?.length === cancellationDetails?.length) { return; } diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts index b5e3f333c44a..458949264ff0 100644 --- a/src/hooks/useDebounce.ts +++ b/src/hooks/useDebounce.ts @@ -42,5 +42,6 @@ export default function useDebounce(func: T, wait: nu } }, []); + // eslint-disable-next-line react-compiler/react-compiler return debounceCallback as T; } diff --git a/src/hooks/useDebouncedState.ts b/src/hooks/useDebouncedState.ts index 8d7d43cb6f9c..b004c308a375 100644 --- a/src/hooks/useDebouncedState.ts +++ b/src/hooks/useDebouncedState.ts @@ -20,6 +20,7 @@ import CONST from '@src/CONST'; function useDebouncedState(initialValue: T, delay: number = CONST.TIMING.USE_DEBOUNCED_STATE_DELAY): [T, T, (value: T) => void] { const [value, setValue] = useState(initialValue); const [debouncedValue, setDebouncedValue] = useState(initialValue); + // eslint-disable-next-line react-compiler/react-compiler const debouncedSetDebouncedValue = useRef(debounce(setDebouncedValue, delay)).current; useEffect(() => () => debouncedSetDebouncedValue.cancel(), [debouncedSetDebouncedValue]); diff --git a/src/hooks/useDeepCompareRef.ts b/src/hooks/useDeepCompareRef.ts index 7511c1516a1d..9a226da44767 100644 --- a/src/hooks/useDeepCompareRef.ts +++ b/src/hooks/useDeepCompareRef.ts @@ -17,8 +17,11 @@ import {useRef} from 'react'; */ export default function useDeepCompareRef(value: T): T | undefined { const ref = useRef(); + // eslint-disable-next-line react-compiler/react-compiler if (!isEqual(value, ref.current)) { + // eslint-disable-next-line react-compiler/react-compiler ref.current = value; } + // eslint-disable-next-line react-compiler/react-compiler return ref.current; } diff --git a/src/hooks/useNetwork.ts b/src/hooks/useNetwork.ts index 950d0592b59c..69aaebc415a5 100644 --- a/src/hooks/useNetwork.ts +++ b/src/hooks/useNetwork.ts @@ -10,6 +10,7 @@ type UseNetwork = {isOffline: boolean}; export default function useNetwork({onReconnect = () => {}}: UseNetworkProps = {}): UseNetwork { const callback = useRef(onReconnect); + // eslint-disable-next-line react-compiler/react-compiler callback.current = onReconnect; const {isOffline, networkStatus} = useContext(NetworkContext) ?? {...CONST.DEFAULT_NETWORK_DATA, networkStatus: CONST.NETWORK.NETWORK_STATUS.UNKNOWN}; diff --git a/src/hooks/usePrevious.ts b/src/hooks/usePrevious.ts index 279e8e4a3bf4..e5db9bffd39c 100644 --- a/src/hooks/usePrevious.ts +++ b/src/hooks/usePrevious.ts @@ -8,5 +8,6 @@ export default function usePrevious(value: T): T { useEffect(() => { ref.current = value; }, [value]); + // eslint-disable-next-line react-compiler/react-compiler return ref.current; } diff --git a/src/hooks/useSingleExecution/index.native.ts b/src/hooks/useSingleExecution/index.native.ts index 16a98152def1..736a79ab1810 100644 --- a/src/hooks/useSingleExecution/index.native.ts +++ b/src/hooks/useSingleExecution/index.native.ts @@ -10,6 +10,7 @@ export default function useSingleExecution() { const [isExecuting, setIsExecuting] = useState(false); const isExecutingRef = useRef(); + // eslint-disable-next-line react-compiler/react-compiler isExecutingRef.current = isExecuting; const singleExecution = useCallback( diff --git a/src/hooks/useSubStep/index.ts b/src/hooks/useSubStep/index.ts index eb4a30037ab0..e59e18cf85b5 100644 --- a/src/hooks/useSubStep/index.ts +++ b/src/hooks/useSubStep/index.ts @@ -59,9 +59,11 @@ export default function useSubStep({bodyContent, on setScreenIndex(bodyContent.length - 1); }, [bodyContent]); + // eslint-disable-next-line react-compiler/react-compiler return { // eslint-disable-next-line @typescript-eslint/non-nullable-type-assertion-style componentToRender: bodyContent.at(screenIndex) as ComponentType, + // eslint-disable-next-line react-compiler/react-compiler isEditing: isEditing.current, screenIndex, prevScreen, diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.tsx b/src/libs/Navigation/AppNavigator/AuthScreens.tsx index 68cc7e748413..85c027f06d95 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.tsx +++ b/src/libs/Navigation/AppNavigator/AuthScreens.tsx @@ -244,6 +244,8 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie let initialReportID: string | undefined; const isInitialRender = useRef(true); + + // eslint-disable-next-line react-compiler/react-compiler if (isInitialRender.current) { Timing.start(CONST.TIMING.HOMEPAGE_INITIAL_RENDER); @@ -257,6 +259,7 @@ function AuthScreens({session, lastOpenedPublicRoomID, initialLastUpdateIDApplie initialReportID = initialReport?.reportID ?? ''; } + // eslint-disable-next-line react-compiler/react-compiler isInitialRender.current = false; } diff --git a/src/libs/Network/enhanceParameters.ts b/src/libs/Network/enhanceParameters.ts index 01d2185a34c6..1806726fdabb 100644 --- a/src/libs/Network/enhanceParameters.ts +++ b/src/libs/Network/enhanceParameters.ts @@ -20,6 +20,15 @@ Onyx.connect({ }, }); +// Check if the user is logged in as a delegate and send that if so +let delegate = ''; +Onyx.connect({ + key: ONYXKEYS.ACCOUNT, + callback: (val) => { + delegate = val?.delegatedAccess?.delegate ?? ''; + }, +}); + /** * Does this command require an authToken? */ @@ -57,5 +66,9 @@ export default function enhanceParameters(command: string, parameters: Record): str function getIntegrationIcon(connectionName?: ConnectionName) { if (connectionName === CONST.POLICY.CONNECTIONS.NAME.XERO) { - return XeroCircle; + return XeroSquare; } if (connectionName === CONST.POLICY.CONNECTIONS.NAME.QBO) { - return QBOCircle; + return QBOSquare; } + if (connectionName === CONST.POLICY.CONNECTIONS.NAME.NETSUITE) { + return NetSuiteSquare; + } + if (connectionName === CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT) { + return IntacctSquare; + } + return undefined; } diff --git a/src/libs/SearchParser/autocompleteParser.js b/src/libs/SearchParser/autocompleteParser.js index a9c8870e2f79..5fc13ac07f17 100644 --- a/src/libs/SearchParser/autocompleteParser.js +++ b/src/libs/SearchParser/autocompleteParser.js @@ -185,17 +185,19 @@ function peg$parse(input, options) { var peg$c7 = "expenseType"; var peg$c8 = "type"; var peg$c9 = "status"; - var peg$c10 = "!="; - var peg$c11 = ">="; - var peg$c12 = ">"; - var peg$c13 = "<="; - var peg$c14 = "<"; - var peg$c15 = "\""; + var peg$c10 = ","; + var peg$c11 = "!="; + var peg$c12 = ">="; + var peg$c13 = ">"; + var peg$c14 = "<="; + var peg$c15 = "<"; + var peg$c16 = "\""; var peg$r0 = /^[:=]/; - var peg$r1 = /^[^"\r\n]/; - var peg$r2 = /^[A-Za-z0-9_@.\/#&+\-\\',;%]/; - var peg$r3 = /^[ \t\r\n]/; + var peg$r1 = /^[^ ,"\t\n\r]/; + var peg$r2 = /^[^"\r\n]/; + var peg$r3 = /^[^ ,\t\n\r]/; + var peg$r4 = /^[ \t\r\n]/; var peg$e0 = peg$otherExpectation("key"); var peg$e1 = peg$literalExpectation("in", false); @@ -208,20 +210,22 @@ function peg$parse(input, options) { var peg$e8 = peg$literalExpectation("expenseType", false); var peg$e9 = peg$literalExpectation("type", false); var peg$e10 = peg$literalExpectation("status", false); - var peg$e11 = peg$otherExpectation("operator"); - var peg$e12 = peg$classExpectation([":", "="], false, false); - var peg$e13 = peg$literalExpectation("!=", false); - var peg$e14 = peg$literalExpectation(">=", false); - var peg$e15 = peg$literalExpectation(">", false); - var peg$e16 = peg$literalExpectation("<=", false); - var peg$e17 = peg$literalExpectation("<", false); - var peg$e18 = peg$otherExpectation("quote"); - var peg$e19 = peg$literalExpectation("\"", false); - var peg$e20 = peg$classExpectation(["\"", "\r", "\n"], true, false); - var peg$e21 = peg$otherExpectation("word"); - var peg$e22 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";", "%"], false, false); - var peg$e23 = peg$otherExpectation("whitespace"); - var peg$e24 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); + var peg$e11 = peg$literalExpectation(",", false); + var peg$e12 = peg$otherExpectation("operator"); + var peg$e13 = peg$classExpectation([":", "="], false, false); + var peg$e14 = peg$literalExpectation("!=", false); + var peg$e15 = peg$literalExpectation(">=", false); + var peg$e16 = peg$literalExpectation(">", false); + var peg$e17 = peg$literalExpectation("<=", false); + var peg$e18 = peg$literalExpectation("<", false); + var peg$e19 = peg$otherExpectation("quote"); + var peg$e20 = peg$classExpectation([" ", ",", "\"", "\t", "\n", "\r"], true, false); + var peg$e21 = peg$literalExpectation("\"", false); + var peg$e22 = peg$classExpectation(["\"", "\r", "\n"], true, false); + var peg$e23 = peg$classExpectation([" ", ",", "\t", "\n", "\r"], true, false); + var peg$e24 = peg$otherExpectation("word"); + var peg$e25 = peg$otherExpectation("whitespace"); + var peg$e26 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); var peg$f0 = function(ranges) { return { autocomplete, ranges }; }; var peg$f1 = function(filters) { return filters.filter(Boolean).flat(); }; @@ -241,21 +245,30 @@ function peg$parse(input, options) { ...value[value.length - 1], }; - return value.map(({ start, length }) => ({ - key, - start, - length, - })); + return value + .filter((filter) => filter.length > 0) + .map(({ start, length }) => ({ + key, + start, + length, + })); }; var peg$f3 = function() { autocomplete = null; }; - var peg$f4 = function(parts) { + var peg$f4 = function(parts, empty) { const ends = location(); const value = parts.flat(); + if (empty) { + value.push(""); + } let count = ends.start.offset; const result = []; value.forEach((filter) => { + let word = filter; + if (word.startsWith('"') && word.endsWith('"') && word.length >= 2) { + word = word.slice(1, -1); + } result.push({ - value: filter, + value: word, start: count, length: filter.length, }); @@ -269,10 +282,10 @@ function peg$parse(input, options) { var peg$f8 = function() { return "gt"; }; var peg$f9 = function() { return "lte"; }; var peg$f10 = function() { return "lt"; }; - var peg$f11 = function(chars) { return chars.join(""); }; - var peg$f12 = function(chars) { - return chars.join("").trim().split(",").filter(Boolean); + var peg$f11 = function(start, inner, end) { + return [...start, '"', ...inner, '"', ...end].join(""); }; + var peg$f12 = function(chars) { return chars.join("").trim(); }; var peg$f13 = function() { return "and"; }; var peg$currPos = options.peg$currPos | 0; var peg$savedPos = peg$currPos; @@ -648,30 +661,63 @@ function peg$parse(input, options) { } function peg$parseidentifier() { - var s0, s1, s2; + var s0, s1, s2, s3, s4; s0 = peg$currPos; - s1 = []; - s2 = peg$parsequotedString(); - if (s2 === peg$FAILED) { - s2 = peg$parsealphanumeric(); + s1 = peg$currPos; + s2 = []; + s3 = peg$parsequotedString(); + if (s3 === peg$FAILED) { + s3 = peg$parsealphanumeric(); } - if (s2 !== peg$FAILED) { - while (s2 !== peg$FAILED) { - s1.push(s2); - s2 = peg$parsequotedString(); - if (s2 === peg$FAILED) { - s2 = peg$parsealphanumeric(); + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 44) { + s4 = peg$c10; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e11); } + } + if (s4 !== peg$FAILED) { + s4 = peg$parsequotedString(); + if (s4 === peg$FAILED) { + s4 = peg$parsealphanumeric(); } + if (s4 === peg$FAILED) { + peg$currPos = s3; + s3 = peg$FAILED; + } else { + s3 = s4; + } + } else { + s3 = s4; } - } else { + } + if (s2.length < 1) { + peg$currPos = s1; s1 = peg$FAILED; + } else { + s1 = s2; } if (s1 !== peg$FAILED) { + if (input.charCodeAt(peg$currPos) === 44) { + s2 = peg$c10; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e11); } + } + if (s2 === peg$FAILED) { + s2 = null; + } peg$savedPos = s0; - s1 = peg$f4(s1); + s0 = peg$f4(s1, s2); + } else { + peg$currPos = s0; + s0 = peg$FAILED; } - s0 = s1; return s0; } @@ -686,7 +732,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e12); } + if (peg$silentFails === 0) { peg$fail(peg$e13); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -695,12 +741,12 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c10) { - s1 = peg$c10; + if (input.substr(peg$currPos, 2) === peg$c11) { + s1 = peg$c11; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e13); } + if (peg$silentFails === 0) { peg$fail(peg$e14); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -709,12 +755,12 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c11) { - s1 = peg$c11; + if (input.substr(peg$currPos, 2) === peg$c12) { + s1 = peg$c12; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } + if (peg$silentFails === 0) { peg$fail(peg$e15); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -724,11 +770,11 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c12; + s1 = peg$c13; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e15); } + if (peg$silentFails === 0) { peg$fail(peg$e16); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -737,12 +783,12 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c13) { - s1 = peg$c13; + if (input.substr(peg$currPos, 2) === peg$c14) { + s1 = peg$c14; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e16); } + if (peg$silentFails === 0) { peg$fail(peg$e17); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -752,11 +798,11 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c14; + s1 = peg$c15; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e17); } + if (peg$silentFails === 0) { peg$fail(peg$e18); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -771,53 +817,89 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e11); } + if (peg$silentFails === 0) { peg$fail(peg$e12); } } return s0; } function peg$parsequotedString() { - var s0, s1, s2, s3; + var s0, s1, s2, s3, s4, s5, s6; peg$silentFails++; s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c15; + s1 = []; + s2 = input.charAt(peg$currPos); + if (peg$r1.test(s2)) { peg$currPos++; } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e19); } + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e20); } } - if (s1 !== peg$FAILED) { - s2 = []; - s3 = input.charAt(peg$currPos); - if (peg$r1.test(s3)) { + while (s2 !== peg$FAILED) { + s1.push(s2); + s2 = input.charAt(peg$currPos); + if (peg$r1.test(s2)) { peg$currPos++; } else { - s3 = peg$FAILED; + s2 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e20); } } - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = input.charAt(peg$currPos); - if (peg$r1.test(s3)) { + } + if (input.charCodeAt(peg$currPos) === 34) { + s2 = peg$c16; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e21); } + } + if (s2 !== peg$FAILED) { + s3 = []; + s4 = input.charAt(peg$currPos); + if (peg$r2.test(s4)) { + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e22); } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = input.charAt(peg$currPos); + if (peg$r2.test(s4)) { peg$currPos++; } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e20); } + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e22); } } } if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c15; + s4 = peg$c16; peg$currPos++; } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e19); } + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e21); } } - if (s3 !== peg$FAILED) { + if (s4 !== peg$FAILED) { + s5 = []; + s6 = input.charAt(peg$currPos); + if (peg$r3.test(s6)) { + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e23); } + } + while (s6 !== peg$FAILED) { + s5.push(s6); + s6 = input.charAt(peg$currPos); + if (peg$r3.test(s6)) { + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e23); } + } + } peg$savedPos = s0; - s0 = peg$f11(s2); + s0 = peg$f11(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -829,7 +911,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e18); } + if (peg$silentFails === 0) { peg$fail(peg$e19); } } return s0; @@ -842,21 +924,21 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = []; s2 = input.charAt(peg$currPos); - if (peg$r2.test(s2)) { + if (peg$r3.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e22); } + if (peg$silentFails === 0) { peg$fail(peg$e23); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { s1.push(s2); s2 = input.charAt(peg$currPos); - if (peg$r2.test(s2)) { + if (peg$r3.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e22); } + if (peg$silentFails === 0) { peg$fail(peg$e23); } } } } else { @@ -870,7 +952,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e21); } + if (peg$silentFails === 0) { peg$fail(peg$e24); } } return s0; @@ -894,25 +976,25 @@ function peg$parse(input, options) { peg$silentFails++; s0 = []; s1 = input.charAt(peg$currPos); - if (peg$r3.test(s1)) { + if (peg$r4.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } + if (peg$silentFails === 0) { peg$fail(peg$e26); } } while (s1 !== peg$FAILED) { s0.push(s1); s1 = input.charAt(peg$currPos); - if (peg$r3.test(s1)) { + if (peg$r4.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } + if (peg$silentFails === 0) { peg$fail(peg$e26); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } + if (peg$silentFails === 0) { peg$fail(peg$e25); } return s0; } diff --git a/src/libs/SearchParser/autocompleteParser.peggy b/src/libs/SearchParser/autocompleteParser.peggy index 003d35485d69..bc96c86eb74d 100644 --- a/src/libs/SearchParser/autocompleteParser.peggy +++ b/src/libs/SearchParser/autocompleteParser.peggy @@ -39,11 +39,13 @@ defaultFilter ...value[value.length - 1], }; - return value.map(({ start, length }) => ({ - key, - start, - length, - })); + return value + .filter((filter) => filter.length > 0) + .map(({ start, length }) => ({ + key, + start, + length, + })); } freeTextFilter = _ identifier _ { autocomplete = null; } @@ -63,14 +65,21 @@ autocompleteKey "key" ) identifier - = parts:(quotedString / alphanumeric)+ { + = parts:(quotedString / alphanumeric)|1.., ","| empty:","? { const ends = location(); const value = parts.flat(); + if (empty) { + value.push(""); + } let count = ends.start.offset; const result = []; value.forEach((filter) => { + let word = filter; + if (word.startsWith('"') && word.endsWith('"') && word.length >= 2) { + word = word.slice(1, -1); + } result.push({ - value: filter, + value: word, start: count, length: filter.length, }); diff --git a/src/libs/SearchParser/baseRules.peggy b/src/libs/SearchParser/baseRules.peggy index 62948fdb573b..7605d888ba43 100644 --- a/src/libs/SearchParser/baseRules.peggy +++ b/src/libs/SearchParser/baseRules.peggy @@ -16,13 +16,13 @@ operator "operator" / "<=" { return "lte"; } / "<" { return "lt"; } -quotedString "quote" = "\"" chars:[^"\r\n]* "\"" { return chars.join(""); } - -alphanumeric "word" - = chars:[A-Za-z0-9_@./#&+\-\\',;%]+ { - return chars.join("").trim().split(",").filter(Boolean); +quotedString "quote" + = start:[^ ,"\t\n\r]* "\"" inner:[^"\r\n]* "\"" end:[^ ,\t\n\r]* { + return [...start, '"', ...inner, '"', ...end].join(""); } +alphanumeric "word" = chars:[^ ,\t\n\r]+ { return chars.join("").trim(); } + logicalAnd = _ { return "and"; } _ "whitespace" = [ \t\r\n]* diff --git a/src/libs/SearchParser/searchParser.js b/src/libs/SearchParser/searchParser.js index 49e819ada3e5..1e8d12f16a32 100644 --- a/src/libs/SearchParser/searchParser.js +++ b/src/libs/SearchParser/searchParser.js @@ -200,17 +200,19 @@ function peg$parse(input, options) { var peg$c17 = "sortBy"; var peg$c18 = "sortOrder"; var peg$c19 = "policyID"; - var peg$c20 = "!="; - var peg$c21 = ">="; - var peg$c22 = ">"; - var peg$c23 = "<="; - var peg$c24 = "<"; - var peg$c25 = "\""; + var peg$c20 = ","; + var peg$c21 = "!="; + var peg$c22 = ">="; + var peg$c23 = ">"; + var peg$c24 = "<="; + var peg$c25 = "<"; + var peg$c26 = "\""; var peg$r0 = /^[:=]/; - var peg$r1 = /^[^"\r\n]/; - var peg$r2 = /^[A-Za-z0-9_@.\/#&+\-\\',;%]/; - var peg$r3 = /^[ \t\r\n]/; + var peg$r1 = /^[^ ,"\t\n\r]/; + var peg$r2 = /^[^"\r\n]/; + var peg$r3 = /^[^ ,\t\n\r]/; + var peg$r4 = /^[ \t\r\n]/; var peg$e0 = peg$otherExpectation("key"); var peg$e1 = peg$literalExpectation("date", false); @@ -234,20 +236,22 @@ function peg$parse(input, options) { var peg$e19 = peg$literalExpectation("sortBy", false); var peg$e20 = peg$literalExpectation("sortOrder", false); var peg$e21 = peg$literalExpectation("policyID", false); - var peg$e22 = peg$otherExpectation("operator"); - var peg$e23 = peg$classExpectation([":", "="], false, false); - var peg$e24 = peg$literalExpectation("!=", false); - var peg$e25 = peg$literalExpectation(">=", false); - var peg$e26 = peg$literalExpectation(">", false); - var peg$e27 = peg$literalExpectation("<=", false); - var peg$e28 = peg$literalExpectation("<", false); - var peg$e29 = peg$otherExpectation("quote"); - var peg$e30 = peg$literalExpectation("\"", false); - var peg$e31 = peg$classExpectation(["\"", "\r", "\n"], true, false); - var peg$e32 = peg$otherExpectation("word"); - var peg$e33 = peg$classExpectation([["A", "Z"], ["a", "z"], ["0", "9"], "_", "@", ".", "/", "#", "&", "+", "-", "\\", "'", ",", ";", "%"], false, false); - var peg$e34 = peg$otherExpectation("whitespace"); - var peg$e35 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); + var peg$e22 = peg$literalExpectation(",", false); + var peg$e23 = peg$otherExpectation("operator"); + var peg$e24 = peg$classExpectation([":", "="], false, false); + var peg$e25 = peg$literalExpectation("!=", false); + var peg$e26 = peg$literalExpectation(">=", false); + var peg$e27 = peg$literalExpectation(">", false); + var peg$e28 = peg$literalExpectation("<=", false); + var peg$e29 = peg$literalExpectation("<", false); + var peg$e30 = peg$otherExpectation("quote"); + var peg$e31 = peg$classExpectation([" ", ",", "\"", "\t", "\n", "\r"], true, false); + var peg$e32 = peg$literalExpectation("\"", false); + var peg$e33 = peg$classExpectation(["\"", "\r", "\n"], true, false); + var peg$e34 = peg$classExpectation([" ", ",", "\t", "\n", "\r"], true, false); + var peg$e35 = peg$otherExpectation("word"); + var peg$e36 = peg$otherExpectation("whitespace"); + var peg$e37 = peg$classExpectation([" ", "\t", "\r", "\n"], false, false); var peg$f0 = function(filters) { return applyDefaults(filters); }; var peg$f1 = function(head, tail) { @@ -287,9 +291,14 @@ function peg$parse(input, options) { return buildFilter(op, field, values); }; var peg$f5 = function(parts) { - const value = parts.flat(); + const value = parts.flat().map((word) => { + if (word.startsWith('"') && word.endsWith('"') && word.length >= 2) { + return word.slice(1,-1); + } + return word; + }); if (value.length > 1) { - return value; + return value.filter((word) => word.length > 0); } return value[0]; }; @@ -299,10 +308,10 @@ function peg$parse(input, options) { var peg$f9 = function() { return "gt"; }; var peg$f10 = function() { return "lte"; }; var peg$f11 = function() { return "lt"; }; - var peg$f12 = function(chars) { return chars.join(""); }; - var peg$f13 = function(chars) { - return chars.join("").trim().split(",").filter(Boolean); + var peg$f12 = function(start, inner, end) { + return [...start, '"', ...inner, '"', ...end].join(""); }; + var peg$f13 = function(chars) { return chars.join("").trim(); }; var peg$f14 = function() { return "and"; }; var peg$currPos = options.peg$currPos | 0; var peg$savedPos = peg$currPos; @@ -747,15 +756,6 @@ function peg$parse(input, options) { s1 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e15); } } - if (s1 === peg$FAILED) { - if (input.substr(peg$currPos, 2) === peg$c6) { - s1 = peg$c6; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } - } - } } } } @@ -849,24 +849,45 @@ function peg$parse(input, options) { } function peg$parseidentifier() { - var s0, s1, s2; + var s0, s1, s2, s3, s4; s0 = peg$currPos; - s1 = []; - s2 = peg$parsequotedString(); - if (s2 === peg$FAILED) { - s2 = peg$parsealphanumeric(); + s1 = peg$currPos; + s2 = []; + s3 = peg$parsequotedString(); + if (s3 === peg$FAILED) { + s3 = peg$parsealphanumeric(); } - if (s2 !== peg$FAILED) { - while (s2 !== peg$FAILED) { - s1.push(s2); - s2 = peg$parsequotedString(); - if (s2 === peg$FAILED) { - s2 = peg$parsealphanumeric(); + while (s3 !== peg$FAILED) { + s2.push(s3); + s3 = peg$currPos; + if (input.charCodeAt(peg$currPos) === 44) { + s4 = peg$c20; + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e22); } + } + if (s4 !== peg$FAILED) { + s4 = peg$parsequotedString(); + if (s4 === peg$FAILED) { + s4 = peg$parsealphanumeric(); } + if (s4 === peg$FAILED) { + peg$currPos = s3; + s3 = peg$FAILED; + } else { + s3 = s4; + } + } else { + s3 = s4; } - } else { + } + if (s2.length < 1) { + peg$currPos = s1; s1 = peg$FAILED; + } else { + s1 = s2; } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -887,7 +908,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e23); } + if (peg$silentFails === 0) { peg$fail(peg$e24); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -896,12 +917,12 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c20) { - s1 = peg$c20; + if (input.substr(peg$currPos, 2) === peg$c21) { + s1 = peg$c21; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e24); } + if (peg$silentFails === 0) { peg$fail(peg$e25); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -910,12 +931,12 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c21) { - s1 = peg$c21; + if (input.substr(peg$currPos, 2) === peg$c22) { + s1 = peg$c22; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e25); } + if (peg$silentFails === 0) { peg$fail(peg$e26); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -925,11 +946,11 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 62) { - s1 = peg$c22; + s1 = peg$c23; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e26); } + if (peg$silentFails === 0) { peg$fail(peg$e27); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -938,12 +959,12 @@ function peg$parse(input, options) { s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c23) { - s1 = peg$c23; + if (input.substr(peg$currPos, 2) === peg$c24) { + s1 = peg$c24; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e27); } + if (peg$silentFails === 0) { peg$fail(peg$e28); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -953,11 +974,11 @@ function peg$parse(input, options) { if (s0 === peg$FAILED) { s0 = peg$currPos; if (input.charCodeAt(peg$currPos) === 60) { - s1 = peg$c24; + s1 = peg$c25; peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e28); } + if (peg$silentFails === 0) { peg$fail(peg$e29); } } if (s1 !== peg$FAILED) { peg$savedPos = s0; @@ -972,53 +993,89 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e22); } + if (peg$silentFails === 0) { peg$fail(peg$e23); } } return s0; } function peg$parsequotedString() { - var s0, s1, s2, s3; + var s0, s1, s2, s3, s4, s5, s6; peg$silentFails++; s0 = peg$currPos; - if (input.charCodeAt(peg$currPos) === 34) { - s1 = peg$c25; + s1 = []; + s2 = input.charAt(peg$currPos); + if (peg$r1.test(s2)) { peg$currPos++; } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e30); } + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e31); } } - if (s1 !== peg$FAILED) { - s2 = []; - s3 = input.charAt(peg$currPos); - if (peg$r1.test(s3)) { + while (s2 !== peg$FAILED) { + s1.push(s2); + s2 = input.charAt(peg$currPos); + if (peg$r1.test(s2)) { peg$currPos++; } else { - s3 = peg$FAILED; + s2 = peg$FAILED; if (peg$silentFails === 0) { peg$fail(peg$e31); } } - while (s3 !== peg$FAILED) { - s2.push(s3); - s3 = input.charAt(peg$currPos); - if (peg$r1.test(s3)) { + } + if (input.charCodeAt(peg$currPos) === 34) { + s2 = peg$c26; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e32); } + } + if (s2 !== peg$FAILED) { + s3 = []; + s4 = input.charAt(peg$currPos); + if (peg$r2.test(s4)) { + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e33); } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = input.charAt(peg$currPos); + if (peg$r2.test(s4)) { peg$currPos++; } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e31); } + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e33); } } } if (input.charCodeAt(peg$currPos) === 34) { - s3 = peg$c25; + s4 = peg$c26; peg$currPos++; } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e30); } + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e32); } } - if (s3 !== peg$FAILED) { + if (s4 !== peg$FAILED) { + s5 = []; + s6 = input.charAt(peg$currPos); + if (peg$r3.test(s6)) { + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e34); } + } + while (s6 !== peg$FAILED) { + s5.push(s6); + s6 = input.charAt(peg$currPos); + if (peg$r3.test(s6)) { + peg$currPos++; + } else { + s6 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e34); } + } + } peg$savedPos = s0; - s0 = peg$f12(s2); + s0 = peg$f12(s1, s3, s5); } else { peg$currPos = s0; s0 = peg$FAILED; @@ -1030,7 +1087,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e29); } + if (peg$silentFails === 0) { peg$fail(peg$e30); } } return s0; @@ -1043,21 +1100,21 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = []; s2 = input.charAt(peg$currPos); - if (peg$r2.test(s2)) { + if (peg$r3.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e33); } + if (peg$silentFails === 0) { peg$fail(peg$e34); } } if (s2 !== peg$FAILED) { while (s2 !== peg$FAILED) { s1.push(s2); s2 = input.charAt(peg$currPos); - if (peg$r2.test(s2)) { + if (peg$r3.test(s2)) { peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e33); } + if (peg$silentFails === 0) { peg$fail(peg$e34); } } } } else { @@ -1071,7 +1128,7 @@ function peg$parse(input, options) { peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e32); } + if (peg$silentFails === 0) { peg$fail(peg$e35); } } return s0; @@ -1095,25 +1152,25 @@ function peg$parse(input, options) { peg$silentFails++; s0 = []; s1 = input.charAt(peg$currPos); - if (peg$r3.test(s1)) { + if (peg$r4.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e35); } + if (peg$silentFails === 0) { peg$fail(peg$e37); } } while (s1 !== peg$FAILED) { s0.push(s1); s1 = input.charAt(peg$currPos); - if (peg$r3.test(s1)) { + if (peg$r4.test(s1)) { peg$currPos++; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e35); } + if (peg$silentFails === 0) { peg$fail(peg$e37); } } } peg$silentFails--; s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e34); } + if (peg$silentFails === 0) { peg$fail(peg$e36); } return s0; } diff --git a/src/libs/SearchParser/searchParser.peggy b/src/libs/SearchParser/searchParser.peggy index f775117b5f4e..7d5815d41459 100644 --- a/src/libs/SearchParser/searchParser.peggy +++ b/src/libs/SearchParser/searchParser.peggy @@ -108,17 +108,21 @@ key "key" / "cardID" / "from" / "expenseType" - / "in" ) defaultKey "default key" = @("type" / "status" / "sortBy" / "sortOrder" / "policyID") identifier - = parts:(quotedString / alphanumeric)+ { - const value = parts.flat(); + = parts:(quotedString / alphanumeric)|1.., ","| { + const value = parts.flat().map((word) => { + if (word.startsWith('"') && word.endsWith('"') && word.length >= 2) { + return word.slice(1,-1); + } + return word; + }); if (value.length > 1) { - return value; + return value.filter((word) => word.length > 0); } return value[0]; } diff --git a/src/libs/SearchQueryUtils.ts b/src/libs/SearchQueryUtils.ts index 32c2eff72007..51db9fd56ea6 100644 --- a/src/libs/SearchQueryUtils.ts +++ b/src/libs/SearchQueryUtils.ts @@ -1,13 +1,15 @@ import cloneDeep from 'lodash/cloneDeep'; import type {OnyxCollection} from 'react-native-onyx'; import type {ValueOf} from 'type-fest'; -import type {AdvancedFiltersKeys, ASTNode, QueryFilter, QueryFilters, SearchQueryJSON, SearchQueryString, SearchStatus} from '@components/Search/types'; +import type {ASTNode, QueryFilter, QueryFilters, SearchQueryJSON, SearchQueryString, SearchStatus} from '@components/Search/types'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import type {SearchAdvancedFiltersForm} from '@src/types/form'; import FILTER_KEYS from '@src/types/form/SearchAdvancedFiltersForm'; import type * as OnyxTypes from '@src/types/onyx'; import type {SearchDataTypes} from '@src/types/onyx/SearchResults'; +import * as CurrencyUtils from './CurrencyUtils'; +import localeCompare from './LocaleCompare'; import {validateAmount} from './MoneyRequestUtils'; import * as PersonalDetailsUtils from './PersonalDetailsUtils'; import {getTagNamesFromTagsLists} from './PolicyUtils'; @@ -115,7 +117,7 @@ function buildFilterValuesString(filterName: string, queryFilters: QueryFilter[] * Traverses the AST and returns filters as a QueryFilters object. */ function getFilters(queryJSON: SearchQueryJSON) { - const filters = {} as QueryFilters; + const filters = [] as QueryFilters; const filterKeys = Object.values(CONST.SEARCH.SYNTAX_FILTER_KEYS); function traverse(node: ASTNode) { @@ -136,12 +138,7 @@ function getFilters(queryJSON: SearchQueryJSON) { return; } - if (!filters[nodeKey]) { - filters[nodeKey] = []; - } - - // the "?? []" is added only for typescript because otherwise TS throws an error, in newer TS versions this should be fixed - const filterArray = filters[nodeKey] ?? []; + const filterArray = []; if (!Array.isArray(node.right)) { filterArray.push({ operator: node.operator, @@ -155,6 +152,7 @@ function getFilters(queryJSON: SearchQueryJSON) { }); }); } + filters.push({key: nodeKey, filters: filterArray}); } if (queryJSON.filters) { @@ -200,6 +198,16 @@ function findIDFromDisplayValue(filterName: ValueOf { + const backendAmount = CurrencyUtils.convertToBackendAmount(Number(amount)); + return Number.isNaN(backendAmount) ? amount : backendAmount.toString(); + }); + } return filter; } @@ -218,18 +226,14 @@ function getQueryHash(query: SearchQueryJSON): number { orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_BY}:${query.sortBy}`; orderedQuery += ` ${CONST.SEARCH.SYNTAX_ROOT_KEYS.SORT_ORDER}:${query.sortOrder}`; - Object.keys(query.flatFilters) + query.flatFilters.forEach((filter) => { + filter.filters.sort((a, b) => localeCompare(a.value.toString(), b.value.toString())); + }); + + query.flatFilters + .map((filter) => buildFilterValuesString(filter.key, filter.filters)) .sort() - .forEach((key) => { - const filterValues = query.flatFilters?.[key as AdvancedFiltersKeys]; - const sortedFilterValues = filterValues?.sort((queryFilter1, queryFilter2) => { - if (queryFilter1.value > queryFilter2.value) { - return 1; - } - return -1; - }); - orderedQuery += ` ${buildFilterValuesString(key, sortedFilterValues ?? [])}`; - }); + .forEach((filterString) => (orderedQuery += ` ${filterString}`)); return UserUtils.hashText(orderedQuery, 2 ** 32); } @@ -281,13 +285,9 @@ function buildSearchQueryString(queryJSON?: SearchQueryJSON) { const filters = queryJSON.flatFilters; - for (const [, filterKey] of Object.entries(CONST.SEARCH.SYNTAX_FILTER_KEYS)) { - const queryFilter = filters[filterKey]; - - if (queryFilter) { - const filterValueString = buildFilterValuesString(filterKey, queryFilter); - queryParts.push(filterValueString); - } + for (const filter of filters) { + const filterValueString = buildFilterValuesString(filter.key, filter.filters); + queryParts.push(filterValueString); } return queryParts.join(' '); @@ -388,32 +388,35 @@ function buildFilterFormValuesFromQuery( taxRates: Record, ) { const filters = queryJSON.flatFilters; - const filterKeys = Object.keys(filters); const filtersForm = {} as Partial; const policyID = queryJSON.policyID; - for (const filterKey of filterKeys) { + for (const queryFilter of filters) { + const filterKey = queryFilter.key; + const filterList = queryFilter.filters; + const filterValues = filterList.map((item) => item.value.toString()); if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.REPORT_ID || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.MERCHANT || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.DESCRIPTION) { - filtersForm[filterKey] = filters[filterKey]?.[0]?.value.toString(); + filtersForm[filterKey] = filterValues.at(0); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.EXPENSE_TYPE) { - filtersForm[filterKey] = filters[filterKey] - ?.map((expenseType) => expenseType.value.toString()) - .filter((expenseType) => Object.values(CONST.SEARCH.TRANSACTION_TYPE).includes(expenseType as ValueOf)); + const validExpenseTypes = new Set(Object.values(CONST.SEARCH.TRANSACTION_TYPE)); + filtersForm[filterKey] = filterValues.filter((expenseType) => validExpenseTypes.has(expenseType as ValueOf)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CARD_ID) { - filtersForm[filterKey] = filters[filterKey]?.map((card) => card.value.toString()).filter((card) => Object.keys(cardList).includes(card)); + filtersForm[filterKey] = filterValues.filter((card) => cardList[card]); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE) { - filtersForm[filterKey] = filters[filterKey]?.map((tax) => tax.value.toString()).filter((tax) => [...Object.values(taxRates)].flat().includes(tax)); + const allTaxRates = new Set(Object.values(taxRates).flat()); + filtersForm[filterKey] = filterValues.filter((tax) => allTaxRates.has(tax)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { - filtersForm[filterKey] = filters[filterKey]?.map((report) => report.value.toString()).filter((id) => reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]); + filtersForm[filterKey] = filterValues.filter((id) => reports?.[`${ONYXKEYS.COLLECTION.REPORT}${id}`]); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.FROM || filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TO) { - filtersForm[filterKey] = filters[filterKey]?.map((id) => id.value.toString()).filter((id) => Object.keys(personalDetails).includes(id)); + filtersForm[filterKey] = filterValues.filter((id) => personalDetails[id]); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CURRENCY) { - filtersForm[filterKey] = filters[filterKey]?.filter((currency) => Object.keys(currencyList).includes(currency.value.toString())).map((currency) => currency.value.toString()); + const validCurrency = new Set(Object.keys(currencyList)); + filtersForm[filterKey] = filterValues.filter((currency) => validCurrency.has(currency)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAG) { const tags = policyID @@ -422,8 +425,9 @@ function buildFilterFormValuesFromQuery( .filter((item) => !!item) .map((tagList) => getTagNamesFromTagsLists(tagList ?? {})) .flat(); - tags.push(CONST.SEARCH.EMPTY_VALUE); - filtersForm[filterKey] = filters[filterKey]?.map((tag) => tag.value.toString()).filter((name) => tags.includes(name)); + const uniqueTags = new Set(tags); + uniqueTags.add(CONST.SEARCH.EMPTY_VALUE); + filtersForm[filterKey] = filterValues.filter((name) => uniqueTags.has(name)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.CATEGORY) { const categories = policyID @@ -431,13 +435,13 @@ function buildFilterFormValuesFromQuery( : Object.values(policyCategories ?? {}) .map((item) => Object.values(item ?? {}).map((category) => category.name)) .flat(); - categories.push(CONST.SEARCH.EMPTY_VALUE); - filtersForm[filterKey] = filters[filterKey]?.map((category) => category.value.toString()).filter((name) => categories.includes(name)); + const uniqueCategories = new Set(categories); + uniqueCategories.add(CONST.SEARCH.EMPTY_VALUE); + filtersForm[filterKey] = filterValues.filter((name) => uniqueCategories.has(name)); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.KEYWORD) { - filtersForm[filterKey] = filters[filterKey] - ?.map((filter) => filter.value.toString()) - .map((filter) => { + filtersForm[filterKey] = filterValues + ?.map((filter) => { if (filter.includes(' ')) { return `"${filter}"`; } @@ -446,12 +450,19 @@ function buildFilterFormValuesFromQuery( .join(' '); } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.DATE) { - filtersForm[FILTER_KEYS.DATE_BEFORE] = filters[filterKey]?.find((filter) => filter.operator === 'lt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString(); - filtersForm[FILTER_KEYS.DATE_AFTER] = filters[filterKey]?.find((filter) => filter.operator === 'gt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString(); + filtersForm[FILTER_KEYS.DATE_BEFORE] = + filterList.find((filter) => filter.operator === 'lt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString() ?? filtersForm[FILTER_KEYS.DATE_BEFORE]; + filtersForm[FILTER_KEYS.DATE_AFTER] = + filterList.find((filter) => filter.operator === 'gt' && ValidationUtils.isValidDate(filter.value.toString()))?.value.toString() ?? filtersForm[FILTER_KEYS.DATE_AFTER]; } if (filterKey === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { - filtersForm[FILTER_KEYS.LESS_THAN] = filters[filterKey]?.find((filter) => filter.operator === 'lt' && validateAmount(filter.value.toString(), 2))?.value.toString(); - filtersForm[FILTER_KEYS.GREATER_THAN] = filters[filterKey]?.find((filter) => filter.operator === 'gt' && validateAmount(filter.value.toString(), 2))?.value.toString(); + // backend amount is an integer and is 2 digits longer than frontend amount + filtersForm[FILTER_KEYS.LESS_THAN] = + filterList.find((filter) => filter.operator === 'lt' && validateAmount(filter.value.toString(), 0, CONST.IOU.AMOUNT_MAX_LENGTH + 2))?.value.toString() ?? + filtersForm[FILTER_KEYS.LESS_THAN]; + filtersForm[FILTER_KEYS.GREATER_THAN] = + filterList.find((filter) => filter.operator === 'gt' && validateAmount(filter.value.toString(), 0, CONST.IOU.AMOUNT_MAX_LENGTH + 2))?.value.toString() ?? + filtersForm[FILTER_KEYS.GREATER_THAN]; } } @@ -503,6 +514,10 @@ function getDisplayValue(filterName: string, filter: string, personalDetails: On if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.IN) { return ReportUtils.getReportName(reports?.[`${ONYXKEYS.COLLECTION.REPORT}${filter}`]) || filter; } + if (filterName === CONST.SEARCH.SYNTAX_FILTER_KEYS.AMOUNT) { + const frontendAmount = CurrencyUtils.convertToFrontendAmountAsInteger(Number(filter)); + return Number.isNaN(frontendAmount) ? filter : frontendAmount.toString(); + } return filter; } @@ -524,8 +539,10 @@ function buildUserReadableQueryString( let title = `type:${type} status:${status}`; - Object.keys(filters).forEach((key) => { - const queryFilter = filters[key as ValueOf] ?? []; + for (const filterObject of filters) { + const key = filterObject.key; + const queryFilter = filterObject.filters; + let displayQueryFilters: QueryFilter[] = []; if (key === CONST.SEARCH.SYNTAX_FILTER_KEYS.TAX_RATE) { const taxRateIDs = queryFilter.map((filter) => filter.value.toString()); @@ -549,7 +566,7 @@ function buildUserReadableQueryString( })); } title += buildFilterValuesString(key, displayQueryFilters); - }); + } return title; } diff --git a/src/pages/LogInWithShortLivedAuthTokenPage.tsx b/src/pages/LogInWithShortLivedAuthTokenPage.tsx index fcbeadaa4a47..e604f2ccf847 100644 --- a/src/pages/LogInWithShortLivedAuthTokenPage.tsx +++ b/src/pages/LogInWithShortLivedAuthTokenPage.tsx @@ -1,8 +1,7 @@ import type {StackScreenProps} from '@react-navigation/stack'; import React, {useEffect} from 'react'; import {NativeModules} from 'react-native'; -import type {OnyxEntry} from 'react-native-onyx'; -import {withOnyx} from 'react-native-onyx'; +import {useOnyx} from 'react-native-onyx'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; @@ -13,18 +12,13 @@ import ONYXKEYS from '@src/ONYXKEYS'; import type {Route} from '@src/ROUTES'; import ROUTES from '@src/ROUTES'; import type SCREENS from '@src/SCREENS'; -import type {Account} from '@src/types/onyx'; import SessionExpiredPage from './ErrorPage/SessionExpiredPage'; -type LogInWithShortLivedAuthTokenPageOnyxProps = { - /** The details about the account that the user is signing in with */ - account: OnyxEntry; -}; +type LogInWithShortLivedAuthTokenPageProps = StackScreenProps; -type LogInWithShortLivedAuthTokenPageProps = LogInWithShortLivedAuthTokenPageOnyxProps & StackScreenProps; - -function LogInWithShortLivedAuthTokenPage({route, account}: LogInWithShortLivedAuthTokenPageProps) { +function LogInWithShortLivedAuthTokenPage({route}: LogInWithShortLivedAuthTokenPageProps) { const {email = '', shortLivedAuthToken = '', shortLivedToken = '', authTokenType, exitTo, error} = route?.params ?? {}; + const [account] = useOnyx(ONYXKEYS.ACCOUNT); useEffect(() => { // We have to check for both shortLivedAuthToken and shortLivedToken, as the old mobile app uses shortLivedToken, and is not being actively updated. @@ -71,6 +65,4 @@ function LogInWithShortLivedAuthTokenPage({route, account}: LogInWithShortLivedA LogInWithShortLivedAuthTokenPage.displayName = 'LogInWithShortLivedAuthTokenPage'; -export default withOnyx({ - account: {key: ONYXKEYS.ACCOUNT}, -})(LogInWithShortLivedAuthTokenPage); +export default LogInWithShortLivedAuthTokenPage; diff --git a/src/pages/NewChatConfirmPage.tsx b/src/pages/NewChatConfirmPage.tsx index d6b199def243..85e33cf0c598 100644 --- a/src/pages/NewChatConfirmPage.tsx +++ b/src/pages/NewChatConfirmPage.tsx @@ -140,6 +140,7 @@ function NewChatConfirmPage({newGroupDraft, allPersonalDetails}: NewChatConfirmP { setAvatarFile(image); diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx index 47c1aadf493a..a6b4d2f88a76 100644 --- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx +++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.tsx @@ -414,6 +414,7 @@ function ReimbursementAccountPage({route, policy}: ReimbursementAccountPageProps // Show loading indicator when page is first time being opened and props.reimbursementAccount yet to be loaded from the server // or when data is being loaded. Don't show the loading indicator if we're offline and restarted the bank account setup process // On Android, when we open the app from the background, Onfido activity gets destroyed, so we need to reopen it. + // eslint-disable-next-line react-compiler/react-compiler if ((!hasACHDataBeenLoaded || isLoading) && shouldShowOfflineLoader && (shouldReopenOnfido || !requestorStepRef.current)) { return ; } diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx index baf3d02d7af3..d141920ac99b 100644 --- a/src/pages/home/ReportScreen.tsx +++ b/src/pages/home/ReportScreen.tsx @@ -228,6 +228,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro const [scrollPosition, setScrollPosition] = useState({}); const wasReportAccessibleRef = useRef(false); + // eslint-disable-next-line react-compiler/react-compiler if (firstRenderRef.current) { Timing.start(CONST.TIMING.CHAT_RENDER); Performance.markStart(CONST.TIMING.CHAT_RENDER); @@ -384,7 +385,9 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro return false; } + // eslint-disable-next-line react-compiler/react-compiler if (!wasReportAccessibleRef.current && !firstRenderRef.current && !reportID && !isOptimisticDelete && !reportMetadata?.isLoadingInitialReportActions && !userLeavingStatus) { + // eslint-disable-next-line react-compiler/react-compiler return true; } diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx index 40ace38a9784..2e92669aa8c5 100755 --- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.tsx @@ -105,6 +105,7 @@ function BaseReportActionContextMenu({ draftMessage = '', reportActionID, reportID, + originalReportID, checkIfContextMenuActive, disabledActions = [], setIsEmojiPickerActive, @@ -120,7 +121,7 @@ function BaseReportActionContextMenu({ const {isProduction} = useEnvironment(); const threedotRef = useRef(null); const [betas] = useOnyx(ONYXKEYS.BETAS); - const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`, { + const [reportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${originalReportID}`, { canEvict: false, }); const transactionID = ReportActionsUtils.getLinkedTransactionID(reportActionID, reportID); @@ -179,8 +180,6 @@ function BaseReportActionContextMenu({ const areHoldRequirementsMet = !isInvoiceReport && isMoneyRequestOrReport && !ReportUtils.isArchivedRoom(transactionThreadReportID ? childReport : parentReport, parentReportNameValuePairs); - const originalReportID = useMemo(() => ReportUtils.getOriginalReportID(reportID, reportAction), [reportID, reportAction]); - const shouldEnableArrowNavigation = !isMini && (isVisible || shouldKeepOpen); let filteredContextMenuActions = ContextMenuActions.filter( (contextAction) => diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx index 3a4c8beb56c9..f387f09d3880 100644 --- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx +++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-compiler/react-compiler */ import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx index f325ef10b56f..f3390fe10694 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions/index.e2e.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react-compiler/react-compiler */ import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useRef} from 'react'; import type {LayoutChangeEvent} from 'react-native'; diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx index 2850ed0538db..ef54f2893660 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx @@ -61,6 +61,7 @@ function SuggestionEmoji( ) { const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues); const suggestionValuesRef = useRef(suggestionValues); + // eslint-disable-next-line react-compiler/react-compiler suggestionValuesRef.current = suggestionValues; const isEmojiSuggestionsMenuVisible = suggestionValues.suggestedEmojis.length > 0 && suggestionValues.shouldShowSuggestionMenu; diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx index 0cb87156cdf2..7a7230fef333 100644 --- a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx +++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx @@ -89,6 +89,7 @@ function SuggestionMention( const {translate, formatPhoneNumber} = useLocalize(); const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues); const suggestionValuesRef = useRef(suggestionValues); + // eslint-disable-next-line react-compiler/react-compiler suggestionValuesRef.current = suggestionValues; const [reports] = useOnyx(ONYXKEYS.COLLECTION.REPORT); @@ -137,8 +138,10 @@ function SuggestionMention( // Used to detect if the selection has changed since the last suggestion insertion // If so, we reset the suggestionInsertionIndexRef + // eslint-disable-next-line react-compiler/react-compiler const hasSelectionChanged = !(selection.end === selection.start && selection.start === suggestionInsertionIndexRef.current); if (hasSelectionChanged) { + // eslint-disable-next-line react-compiler/react-compiler suggestionInsertionIndexRef.current = null; } diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx index 84bea2600ddf..fd2dc2d44d4b 100644 --- a/src/pages/home/report/ReportActionItemMessageEdit.tsx +++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx @@ -243,6 +243,7 @@ function ReportActionItemMessageEdit( */ const debouncedSaveDraft = useMemo( () => + // eslint-disable-next-line react-compiler/react-compiler lodashDebounce((newDraft: string) => { Report.saveReportActionDraft(reportID, action, newDraft); isCommentPendingSaved.current = false; @@ -559,6 +560,7 @@ function ReportActionItemMessageEdit( + {/* eslint-disable-next-line react-compiler/react-compiler */} {allAncestors.map((ancestor) => ( = useMemo( @@ -569,6 +572,7 @@ function ReportActionsList({ loadOlderChats(true); }, [loadOlderChats]); + // eslint-disable-next-line react-compiler/react-compiler const listFooterComponent = useMemo(() => { // Skip this hook on the first render (when online), as we are not sure if more actions are going to be loaded, // Therefore showing the skeleton on footer might be misleading. @@ -604,6 +608,7 @@ function ReportActionsList({ [onContentSizeChange], ); + // eslint-disable-next-line react-compiler/react-compiler const retryLoadNewerChatsError = useCallback(() => { loadNewerChats(true); }, [loadNewerChats]); @@ -611,6 +616,7 @@ function ReportActionsList({ const listHeaderComponent = useMemo(() => { // In case of an error we want to display the header no matter what. if (!canShowHeader && !hasLoadingNewerReportActionsError) { + // eslint-disable-next-line react-compiler/react-compiler hasHeaderRendered.current = true; return null; } diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx index 8c0f4acbbe39..d74dc84249d4 100644 --- a/src/pages/home/report/withReportOrNotFound.tsx +++ b/src/pages/home/report/withReportOrNotFound.tsx @@ -85,6 +85,7 @@ export default function ( // If the content was shown, but it's not anymore, that means the report was deleted, and we are probably navigating out of this screen. // Return null for this case to avoid rendering FullScreenLoadingIndicator or NotFoundPage when animating transition. + // eslint-disable-next-line react-compiler/react-compiler if (shouldShowNotFoundPage && contentShown.current) { return null; } @@ -98,7 +99,9 @@ export default function ( } } + // eslint-disable-next-line react-compiler/react-compiler if (!contentShown.current) { + // eslint-disable-next-line react-compiler/react-compiler contentShown.current = true; } diff --git a/src/pages/home/sidebar/SidebarLinksData.tsx b/src/pages/home/sidebar/SidebarLinksData.tsx index e5a74db796d8..7dfbdbaf7299 100644 --- a/src/pages/home/sidebar/SidebarLinksData.tsx +++ b/src/pages/home/sidebar/SidebarLinksData.tsx @@ -50,6 +50,7 @@ function SidebarLinksData({insets, isLoadingApp = true, onLinkClick, priorityMod const isLoading = isLoadingApp; const currentReportIDRef = useRef(currentReportID); + // eslint-disable-next-line react-compiler/react-compiler currentReportIDRef.current = currentReportID; const isActiveReport = useCallback((reportID: string): boolean => currentReportIDRef.current === reportID, []); diff --git a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx index db7aac8268e6..d9f65c451f3c 100644 --- a/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx +++ b/src/pages/iou/request/step/IOURequestStepScan/index.native.tsx @@ -139,6 +139,7 @@ function IOURequestStepScan({ const tapGesture = Gesture.Tap() .enabled(device?.supportsFocus ?? false) + // eslint-disable-next-line react-compiler/react-compiler .onStart((ev: {x: number; y: number}) => { const point = {x: ev.x, y: ev.y}; diff --git a/src/pages/settings/AboutPage/ConsolePage.tsx b/src/pages/settings/AboutPage/ConsolePage.tsx index b156a6c7b2f1..c9124fe814c3 100644 --- a/src/pages/settings/AboutPage/ConsolePage.tsx +++ b/src/pages/settings/AboutPage/ConsolePage.tsx @@ -96,6 +96,7 @@ function ConsolePage() { .reverse(); }, [capturedLogs, shouldStoreLogs]); + // eslint-disable-next-line react-compiler/react-compiler const logsList = useMemo(() => getLogs(), [getLogs]); const filteredLogsList = useMemo(() => logsList.filter((log) => log.message.includes(activeFilterIndex)), [activeFilterIndex, logsList]); diff --git a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx index 6f433957015f..a6ed5ca1b53e 100644 --- a/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx +++ b/src/pages/settings/Security/AddDelegate/AddDelegatePage.tsx @@ -40,6 +40,7 @@ function useOptions() { const headerMessage = OptionsListUtils.getHeaderMessage((recentReports?.length || 0) + (personalDetails?.length || 0) !== 0, !!userToInvite, ''); if (isLoading) { + // eslint-disable-next-line react-compiler/react-compiler setIsLoading(false); } diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx index 729faae5e90b..1068cf97197e 100644 --- a/src/pages/signin/SignInPage.tsx +++ b/src/pages/signin/SignInPage.tsx @@ -315,6 +315,7 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale, login={login} onLoginChanged={setLogin} blurOnSubmit={account?.validated === false} + // eslint-disable-next-line react-compiler/react-compiler scrollPageToTop={signInPageLayoutRef.current?.scrollPageToTop} /> {shouldShouldSignUpWelcomeForm && } diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.tsx b/src/pages/tasks/TaskAssigneeSelectorModal.tsx index 5a0912de45a5..59ebe08e41a4 100644 --- a/src/pages/tasks/TaskAssigneeSelectorModal.tsx +++ b/src/pages/tasks/TaskAssigneeSelectorModal.tsx @@ -52,6 +52,7 @@ function useOptions() { const headerMessage = OptionsListUtils.getHeaderMessage((recentReports?.length || 0) + (personalDetails?.length || 0) !== 0 || !!currentUserOption, !!userToInvite, ''); if (isLoading) { + // eslint-disable-next-line react-compiler/react-compiler setIsLoading(false); } diff --git a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx index 56cf5a0eb90b..1c952617dab5 100644 --- a/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx +++ b/src/pages/workspace/workflows/approvals/WorkspaceWorkflowsApprovalsApproverPage.tsx @@ -117,6 +117,7 @@ function WorkspaceWorkflowsApprovalsApproverPage({policy, personalDetails, isLoa .filter((approver): approver is SelectionListApprover => !!approver); approvers.push(...availableApprovers); + // eslint-disable-next-line react-compiler/react-compiler setAllApprovers(approvers); } diff --git a/src/styles/index.ts b/src/styles/index.ts index 1bd77a7974e5..5b04a7a8eace 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -5264,6 +5264,11 @@ const styles = (theme: ThemeColors) => backgroundColor: theme.border, }, + integrationIcon: { + overflow: 'hidden', + borderRadius: variables.buttonBorderRadius, + }, + colorGreenSuccess: { color: colors.green400, }, diff --git a/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts b/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts index 1894f95a44c1..0bf999e7a8d6 100644 --- a/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts +++ b/src/styles/utils/generators/ReportActionContextMenuStyleUtils.ts @@ -19,8 +19,6 @@ const getMiniWrapperStyle = (theme: ThemeColors, styles: ThemeStyles): ViewStyle borderRadius: variables.buttonBorderRadius, borderWidth: 1, borderColor: theme.border, - // In Safari, when welcome messages use a code block (triple backticks), they would overlap the context menu below when there is no scrollbar without the transform style. - transform: 'translateZ(0)', }, ]; diff --git a/src/styles/variables.ts b/src/styles/variables.ts index dc6655791489..4e9bf50e3c8e 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -83,6 +83,7 @@ export default { iconSizeExtraLarge: 40, iconSizeSuperLarge: 60, iconSizeUltraLarge: 80, + iconSizeMenuItem: 32, iconBottomBar: 24, sidebarAvatarSize: 28, iconHeader: 48,