From 68b2444a762ab9bf8a604a6c5d34891225f51c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Tue, 19 Sep 2023 17:41:02 +0200 Subject: [PATCH 001/128] migrate SelectionScraper --- .../{index.native.js => index.native.ts} | 0 .../SelectionScraper/{index.js => index.ts} | 71 ++++++++++--------- 2 files changed, 37 insertions(+), 34 deletions(-) rename src/libs/SelectionScraper/{index.native.js => index.native.ts} (100%) rename src/libs/SelectionScraper/{index.js => index.ts} (72%) diff --git a/src/libs/SelectionScraper/index.native.js b/src/libs/SelectionScraper/index.native.ts similarity index 100% rename from src/libs/SelectionScraper/index.native.js rename to src/libs/SelectionScraper/index.native.ts diff --git a/src/libs/SelectionScraper/index.js b/src/libs/SelectionScraper/index.ts similarity index 72% rename from src/libs/SelectionScraper/index.js rename to src/libs/SelectionScraper/index.ts index 44b87deba796..79639cd0f28a 100644 --- a/src/libs/SelectionScraper/index.js +++ b/src/libs/SelectionScraper/index.ts @@ -1,7 +1,7 @@ import render from 'dom-serializer'; import {parseDocument} from 'htmlparser2'; -import _ from 'underscore'; import Str from 'expensify-common/lib/str'; +import {DataNode, Element, Node} from 'domhandler'; import CONST from '../../CONST'; const elementsWillBeSkipped = ['html', 'body']; @@ -9,17 +9,17 @@ const tagAttribute = 'data-testid'; /** * Reads html of selection. If browser doesn't support Selection API, returns empty string. - * @returns {String} HTML of selection as String */ -const getHTMLOfSelection = () => { +const getHTMLOfSelection = (): string => { // If browser doesn't support Selection API, return an empty string. - if (!window.getSelection) { + const selection = window.getSelection(); + + if (!selection || !window.getSelection) { return ''; } - const selection = window.getSelection(); if (selection.rangeCount <= 0) { - return window.getSelection().toString(); + return window.getSelection()?.toString() ?? ''; } const div = document.createElement('div'); @@ -64,17 +64,17 @@ const getHTMLOfSelection = () => { // and finally commonAncestorContainer.parentNode.closest('data-testid') is targeted dom. if (range.commonAncestorContainer instanceof HTMLElement) { parent = range.commonAncestorContainer.closest(`[${tagAttribute}]`); - } else { - parent = range.commonAncestorContainer.parentNode.closest(`[${tagAttribute}]`); + } else if (range.commonAncestorContainer.parentNode) { + parent = (range.commonAncestorContainer.parentNode as HTMLElement).closest(`[${tagAttribute}]`); } // Keep traversing up to clone all parents with 'data-testid' attribute. while (parent) { const cloned = parent.cloneNode(); cloned.appendChild(child); - child = cloned; + child = cloned as DocumentFragment; - parent = parent.parentNode.closest(`[${tagAttribute}]`); + parent = (parent.parentNode as HTMLElement).closest(`[${tagAttribute}]`); } div.appendChild(child); @@ -96,58 +96,61 @@ const getHTMLOfSelection = () => { /** * Clears all attributes from dom elements - * @param {Object} dom htmlparser2 dom representation - * @param {Boolean} isChildOfEditorElement - * @returns {Object} htmlparser2 dom representation */ -const replaceNodes = (dom, isChildOfEditorElement) => { - let domName = dom.name; - let domChildren; - const domAttribs = {}; - let data; +const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { + const domElement = dom as Element; + let domName = domElement.name; + let domChildren: Node[] = []; + const domAttribs = {} as Element['attribs']; + let data = ''; // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. - if (dom.type === 'text') { - data = Str.htmlEncode(dom.data); + if (dom.type.toString() === 'text') { + data = Str.htmlEncode((dom as DataNode).data); } // We are skipping elements which has html and body in data-testid, since ExpensiMark can't parse it. Also this data // has no meaning for us. - if (dom.attribs && dom.attribs[tagAttribute]) { - if (!elementsWillBeSkipped.includes(dom.attribs[tagAttribute])) { - domName = dom.attribs[tagAttribute]; + if (domElement.attribs?.[tagAttribute]) { + if (!elementsWillBeSkipped.includes(domElement.attribs[tagAttribute])) { + domName = domElement.attribs[tagAttribute]; } - } else if (dom.name === 'div' && dom.children.length === 1 && isChildOfEditorElement) { + } else if (domElement.name === 'div' && domElement.children.length === 1 && isChildOfEditorElement) { // We are excluding divs that are children of our editor element and have only one child to prevent // additional newlines from being added in the HTML to Markdown conversion process. - return replaceNodes(dom.children[0], isChildOfEditorElement); + return replaceNodes(domElement.children[0], isChildOfEditorElement); } // We need to preserve href attribute in order to copy links. - if (dom.attribs && dom.attribs.href) { - domAttribs.href = dom.attribs.href; + if (domElement.attribs?.href) { + domAttribs.href = domElement.attribs.href; + } + + if (domElement.children) { + domChildren = domElement.children.map((c) => replaceNodes(c, isChildOfEditorElement || !!domElement.attribs?.[tagAttribute])); } - if (dom.children) { - domChildren = _.map(dom.children, (c) => replaceNodes(c, isChildOfEditorElement || !_.isEmpty(dom.attribs && dom.attribs[tagAttribute]))); + if (data) { + return { + ...dom, + data, + } as DataNode; } return { ...dom, - data, name: domName, attribs: domAttribs, children: domChildren, - }; + } as Element; }; /** * Resolves the current selection to values and produces clean HTML. - * @returns {String} resolved selection in the HTML format */ -const getCurrentSelection = () => { +const getCurrentSelection = (): string => { const domRepresentation = parseDocument(getHTMLOfSelection()); - domRepresentation.children = _.map(domRepresentation.children, replaceNodes); + domRepresentation.children = domRepresentation.children.map((item) => replaceNodes(item, false)); // Newline characters need to be removed here because the HTML could contain both newlines and
tags, and when //
tags are converted later to markdown, it creates duplicate newline characters. This means that when the content From 43adfe9e58fd0c7e78ec5edaef30be0d9ab8d01f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Thu, 21 Sep 2023 15:06:18 +0200 Subject: [PATCH 002/128] review changes --- src/libs/SelectionScraper/index.native.ts | 8 ++++++-- src/libs/SelectionScraper/index.ts | 7 ++++--- src/libs/SelectionScraper/types.ts | 3 +++ 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 src/libs/SelectionScraper/types.ts diff --git a/src/libs/SelectionScraper/index.native.ts b/src/libs/SelectionScraper/index.native.ts index 3872ece30b66..7712906f05e6 100644 --- a/src/libs/SelectionScraper/index.native.ts +++ b/src/libs/SelectionScraper/index.native.ts @@ -1,4 +1,8 @@ +import GetCurrentSelection from './types'; + +// This is a no-op function for native devices because they wouldn't be able to support Selection API like a website. +const getCurrentSelection: GetCurrentSelection = () => ''; + export default { - // This is a no-op function for native devices because they wouldn't be able to support Selection API like a website. - getCurrentSelection: () => '', + getCurrentSelection, }; diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index 79639cd0f28a..6660d5a394cb 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -3,6 +3,7 @@ import {parseDocument} from 'htmlparser2'; import Str from 'expensify-common/lib/str'; import {DataNode, Element, Node} from 'domhandler'; import CONST from '../../CONST'; +import GetCurrentSelection from './types'; const elementsWillBeSkipped = ['html', 'body']; const tagAttribute = 'data-testid'; @@ -44,7 +45,7 @@ const getHTMLOfSelection = (): string => { // If clonedSelection has no text content this data has no meaning to us. if (clonedSelection.textContent) { - let parent; + let parent: globalThis.Element | null = null; let child = clonedSelection; // If selection starts and ends within same text node we use its parentNode. This is because we can't @@ -101,7 +102,7 @@ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { const domElement = dom as Element; let domName = domElement.name; let domChildren: Node[] = []; - const domAttribs = {} as Element['attribs']; + const domAttribs: Element['attribs'] = {}; let data = ''; // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. @@ -148,7 +149,7 @@ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { /** * Resolves the current selection to values and produces clean HTML. */ -const getCurrentSelection = (): string => { +const getCurrentSelection: GetCurrentSelection = () => { const domRepresentation = parseDocument(getHTMLOfSelection()); domRepresentation.children = domRepresentation.children.map((item) => replaceNodes(item, false)); diff --git a/src/libs/SelectionScraper/types.ts b/src/libs/SelectionScraper/types.ts new file mode 100644 index 000000000000..d33338883dd4 --- /dev/null +++ b/src/libs/SelectionScraper/types.ts @@ -0,0 +1,3 @@ +type GetCurrentSelection = () => string; + +export default GetCurrentSelection; From 6841a5407f3303696ebde4c00ea920215ca99109 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Fri, 22 Sep 2023 11:40:35 +0200 Subject: [PATCH 003/128] add return comment --- src/libs/SelectionScraper/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index 6660d5a394cb..52fe69fcb75e 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -10,6 +10,7 @@ const tagAttribute = 'data-testid'; /** * Reads html of selection. If browser doesn't support Selection API, returns empty string. + * @returns HTML of selection as String */ const getHTMLOfSelection = (): string => { // If browser doesn't support Selection API, return an empty string. From decc2982e22af9f257c2798a73b06ffb2a8e8f04 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Thu, 28 Sep 2023 12:16:41 +0800 Subject: [PATCH 004/128] run webpack dev on https --- config/webpack/webpack.dev.js | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index 19999491395e..c8af82d1d855 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -1,8 +1,8 @@ const path = require('path'); const portfinder = require('portfinder'); -const {DefinePlugin} = require('webpack'); -const {merge} = require('webpack-merge'); -const {TimeAnalyticsPlugin} = require('time-analytics-webpack-plugin'); +const { DefinePlugin } = require('webpack'); +const { merge } = require('webpack-merge'); +const { TimeAnalyticsPlugin } = require('time-analytics-webpack-plugin'); const getCommonConfig = require('./webpack.common'); const BASE_PORT = 8082; @@ -13,20 +13,20 @@ const BASE_PORT = 8082; * @returns {Configuration} */ module.exports = (env = {}) => - portfinder.getPortPromise({port: BASE_PORT}).then((port) => { + portfinder.getPortPromise({ port: BASE_PORT }).then((port) => { // Check if the USE_WEB_PROXY variable has been provided // and rewrite any requests to the local proxy server const proxySettings = process.env.USE_WEB_PROXY === 'false' ? {} : { - proxy: { - '/api': 'http://[::1]:9000', - '/staging': 'http://[::1]:9000', - '/chat-attachments': 'http://[::1]:9000', - '/receipts': 'http://[::1]:9000', - }, - }; + proxy: { + '/api': 'http://[::1]:9000', + '/staging': 'http://[::1]:9000', + '/chat-attachments': 'http://[::1]:9000', + '/receipts': 'http://[::1]:9000', + }, + }; const baseConfig = getCommonConfig(env); @@ -44,6 +44,7 @@ module.exports = (env = {}) => ...proxySettings, historyApiFallback: true, port, + https: true, }, plugins: [ new DefinePlugin({ From b0f3f2371e557b73ce96b51488410ff5300014df Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Fri, 29 Sep 2023 10:38:38 +0800 Subject: [PATCH 005/128] add task to generate certificates --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index d013caa1c402..f7f329363145 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,8 @@ "test:e2e": "node tests/e2e/testRunner.js --development", "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", "workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh", - "workflow-test:generate": "node workflow_tests/utils/preGenerateTest.js" + "workflow-test:generate": "node workflow_tests/utils/preGenerateTest.js", + "setup-https": "mkcert -install && mkcert -cert-file config/webpack/certificate.pem -key-file config/webpack/key.pem new.expensify.com.dev localhost 127.0.0.1" }, "dependencies": { "@expensify/react-native-web": "0.18.15", From 325213a4d9b48095682c3c6b30d7a7fbee39910f Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Fri, 29 Sep 2023 10:39:11 +0800 Subject: [PATCH 006/128] use generated certs in webpack dev --- config/webpack/webpack.dev.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index c8af82d1d855..5c705257ab2a 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -44,7 +44,10 @@ module.exports = (env = {}) => ...proxySettings, historyApiFallback: true, port, - https: true, + https: { + key: path.join(__dirname, 'key.pem'), + cert: path.join(__dirname, 'certificate.pem') + } }, plugins: [ new DefinePlugin({ From c46d0fa0d3ed1ff08b762416be6d09659e612e91 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Fri, 29 Sep 2023 10:39:59 +0800 Subject: [PATCH 007/128] update gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index d3b4daac04d7..335efdc5586a 100644 --- a/.gitignore +++ b/.gitignore @@ -111,3 +111,6 @@ tsconfig.tsbuildinfo # Yalc .yalc yalc.lock + +# Local https certificate/key +config/webpack/*.pem From 0140258f2a40fe513c40d79abb644f39ed9aff5b Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Fri, 29 Sep 2023 12:07:45 +0800 Subject: [PATCH 008/128] add mkcert instructions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index fce7cee8dcdd..537f0d0101ad 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,18 @@ These instructions should get you set up ready to work on New Expensify ๐Ÿ™Œ 1. Install `nvm` then `node` & `npm`: `brew install nvm && nvm install` 2. Install `watchman`: `brew install watchman` 3. Install dependencies: `npm install` +4. Install `mkcert`: `brew install mkcert` followed by `npm run setup-https`. If you're using another OS, follow the instructions [here](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation). You can use any IDE or code editing tool for developing on any platform. Use your favorite! ## Recommended `node` setup In order to have more consistent builds, we use a strict `node` and `npm` version as defined in the `package.json` `engines` field and `.nvmrc` file. `npm install` will fail if you do not use the version defined, so it is recommended to install `node` via `nvm` for easy node version management. Automatic `node` version switching can be installed for [`zsh`](https://github.com/nvm-sh/nvm#zsh) or [`bash`](https://github.com/nvm-sh/nvm#bash) using `nvm`. +## Configuring HTTPS +The webpack development server now uses https. If you're using a mac, you can simply run `npm run setup-https`. + +If you're using another operating system, you will need to ensure `mkcert` is installed, and then follow the instructions in the repository to generate certificates valid for `new.expesify.com.dev` and `localhost`. The certificate should be named `certificate.pem` and the key should be named `key.pem`. They should be placed in `config/webpack`. + ## Running the web app ๐Ÿ•ธ * To run the **development web app**: `npm run web` * Changes applied to Javascript will be applied automatically via WebPack as configured in `webpack.dev.js` From 34b573291053ef606ff1e346fb825518190d2d34 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Fri, 29 Sep 2023 12:08:02 +0800 Subject: [PATCH 009/128] prettier --- config/webpack/webpack.dev.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index 5c705257ab2a..ac7696293b76 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -1,8 +1,8 @@ const path = require('path'); const portfinder = require('portfinder'); -const { DefinePlugin } = require('webpack'); -const { merge } = require('webpack-merge'); -const { TimeAnalyticsPlugin } = require('time-analytics-webpack-plugin'); +const {DefinePlugin} = require('webpack'); +const {merge} = require('webpack-merge'); +const {TimeAnalyticsPlugin} = require('time-analytics-webpack-plugin'); const getCommonConfig = require('./webpack.common'); const BASE_PORT = 8082; @@ -13,20 +13,20 @@ const BASE_PORT = 8082; * @returns {Configuration} */ module.exports = (env = {}) => - portfinder.getPortPromise({ port: BASE_PORT }).then((port) => { + portfinder.getPortPromise({port: BASE_PORT}).then((port) => { // Check if the USE_WEB_PROXY variable has been provided // and rewrite any requests to the local proxy server const proxySettings = process.env.USE_WEB_PROXY === 'false' ? {} : { - proxy: { - '/api': 'http://[::1]:9000', - '/staging': 'http://[::1]:9000', - '/chat-attachments': 'http://[::1]:9000', - '/receipts': 'http://[::1]:9000', - }, - }; + proxy: { + '/api': 'http://[::1]:9000', + '/staging': 'http://[::1]:9000', + '/chat-attachments': 'http://[::1]:9000', + '/receipts': 'http://[::1]:9000', + }, + }; const baseConfig = getCommonConfig(env); @@ -46,8 +46,8 @@ module.exports = (env = {}) => port, https: { key: path.join(__dirname, 'key.pem'), - cert: path.join(__dirname, 'certificate.pem') - } + cert: path.join(__dirname, 'certificate.pem'), + }, }, plugins: [ new DefinePlugin({ From 2d80cbd1ea5044a0e2a54334a13a7d51fa69bb68 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Fri, 29 Sep 2023 16:22:42 +0800 Subject: [PATCH 010/128] change host to new.expensify.com.dev --- README.md | 4 ++++ config/webpack/webpack.dev.js | 1 + 2 files changed, 5 insertions(+) diff --git a/README.md b/README.md index 537f0d0101ad..6b5f96de6b72 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,10 @@ These instructions should get you set up ready to work on New Expensify ๐Ÿ™Œ 2. Install `watchman`: `brew install watchman` 3. Install dependencies: `npm install` 4. Install `mkcert`: `brew install mkcert` followed by `npm run setup-https`. If you're using another OS, follow the instructions [here](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation). +5. Create a host entry in your local hosts file, `/etc/hosts` for new.expensify.com.dev pointing to localhost: +``` +127.0.0.1 new.expensify.com.dev +``` You can use any IDE or code editing tool for developing on any platform. Use your favorite! diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index ac7696293b76..1e7074b16277 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -44,6 +44,7 @@ module.exports = (env = {}) => ...proxySettings, historyApiFallback: true, port, + host: 'new.expensify.com.dev', https: { key: path.join(__dirname, 'key.pem'), cert: path.join(__dirname, 'certificate.pem'), From d7b9c815938dbdf97302e80895da2e6210b92d77 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Fri, 29 Sep 2023 11:39:56 +0200 Subject: [PATCH 011/128] Migrate environment lib to TS --- .../{Environment.js => Environment.ts} | 25 ++++++------------- .../{index.android.js => index.android.ts} | 11 +++++--- .../{index.ios.js => index.ios.ts} | 6 ++--- .../betaChecker/{index.js => index.ts} | 4 +-- .../{index.native.js => index.native.ts} | 11 +++----- .../getEnvironment/{index.js => index.ts} | 7 ++---- 6 files changed, 24 insertions(+), 40 deletions(-) rename src/libs/Environment/{Environment.js => Environment.ts} (69%) rename src/libs/Environment/betaChecker/{index.android.js => index.android.ts} (89%) rename src/libs/Environment/betaChecker/{index.ios.js => index.ios.ts} (67%) rename src/libs/Environment/betaChecker/{index.js => index.ts} (70%) rename src/libs/Environment/getEnvironment/{index.native.js => index.native.ts} (75%) rename src/libs/Environment/getEnvironment/{index.js => index.ts} (53%) diff --git a/src/libs/Environment/Environment.js b/src/libs/Environment/Environment.ts similarity index 69% rename from src/libs/Environment/Environment.js rename to src/libs/Environment/Environment.ts index c039b49d33aa..f14e21eac90d 100644 --- a/src/libs/Environment/Environment.js +++ b/src/libs/Environment/Environment.ts @@ -1,5 +1,4 @@ import Config from 'react-native-config'; -import lodashGet from 'lodash/get'; import CONST from '../../CONST'; import getEnvironment from './getEnvironment'; import CONFIG from '../../CONFIG'; @@ -20,40 +19,32 @@ const OLDDOT_ENVIRONMENT_URLS = { /** * Are we running the app in development? - * - * @return {boolean} */ -function isDevelopment() { - return lodashGet(Config, 'ENVIRONMENT', CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.DEV; +function isDevelopment(): boolean { + return (Config?.ENVIRONMENT ?? CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.DEV; } /** * Are we running an internal test build? - * - * @return {boolean} */ -function isInternalTestBuild() { - return lodashGet(Config, 'ENVIRONMENT', CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.ADHOC && lodashGet(Config, 'PULL_REQUEST_NUMBER', ''); +function isInternalTestBuild(): boolean { + return !!((Config?.ENVIRONMENT ?? CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.ADHOC && (Config?.PULL_REQUEST_NUMBER ?? '')); } /** * Get the URL based on the environment we are in - * - * @returns {Promise} */ -function getEnvironmentURL() { +function getEnvironmentURL(): Promise { return new Promise((resolve) => { - getEnvironment().then((environment) => resolve(ENVIRONMENT_URLS[environment])); + getEnvironment().then((environment) => resolve(ENVIRONMENT_URLS[environment as keyof typeof ENVIRONMENT_URLS])); }); } /** * Get the corresponding oldDot URL based on the environment we are in - * - * @returns {Promise} */ -function getOldDotEnvironmentURL() { - return getEnvironment().then((environment) => OLDDOT_ENVIRONMENT_URLS[environment]); +function getOldDotEnvironmentURL(): Promise { + return getEnvironment().then((environment) => OLDDOT_ENVIRONMENT_URLS[environment as keyof typeof OLDDOT_ENVIRONMENT_URLS]); } export {getEnvironment, isInternalTestBuild, isDevelopment, getEnvironmentURL, getOldDotEnvironmentURL}; diff --git a/src/libs/Environment/betaChecker/index.android.js b/src/libs/Environment/betaChecker/index.android.ts similarity index 89% rename from src/libs/Environment/betaChecker/index.android.js rename to src/libs/Environment/betaChecker/index.android.ts index e74648973c34..8b3afed3b2f3 100644 --- a/src/libs/Environment/betaChecker/index.android.js +++ b/src/libs/Environment/betaChecker/index.android.ts @@ -8,15 +8,18 @@ import * as AppUpdate from '../../actions/AppUpdate'; let isLastSavedBeta = false; Onyx.connect({ key: ONYXKEYS.IS_BETA, - callback: (value) => (isLastSavedBeta = value), + callback: (value) => { + if (!value) { + return; + } + isLastSavedBeta = value; + }, }); /** * Check the GitHub releases to see if the current build is a beta build or production build - * - * @returns {Promise} */ -function isBetaBuild() { +function isBetaBuild(): Promise { return new Promise((resolve) => { fetch(CONST.GITHUB_RELEASE_URL) .then((res) => res.json()) diff --git a/src/libs/Environment/betaChecker/index.ios.js b/src/libs/Environment/betaChecker/index.ios.ts similarity index 67% rename from src/libs/Environment/betaChecker/index.ios.js rename to src/libs/Environment/betaChecker/index.ios.ts index 65b3ea935b04..2d6079e30a1c 100644 --- a/src/libs/Environment/betaChecker/index.ios.js +++ b/src/libs/Environment/betaChecker/index.ios.ts @@ -2,12 +2,10 @@ import {NativeModules} from 'react-native'; /** * Check to see if the build is staging (TestFlight) or production - * - * @returns {Promise} */ -function isBetaBuild() { +function isBetaBuild(): Promise { return new Promise((resolve) => { - NativeModules.EnvironmentChecker.isBeta().then((isBeta) => { + NativeModules.EnvironmentChecker.isBeta().then((isBeta: boolean) => { resolve(isBeta); }); }); diff --git a/src/libs/Environment/betaChecker/index.js b/src/libs/Environment/betaChecker/index.ts similarity index 70% rename from src/libs/Environment/betaChecker/index.js rename to src/libs/Environment/betaChecker/index.ts index 9d0d4af5741b..cda7c297624f 100644 --- a/src/libs/Environment/betaChecker/index.js +++ b/src/libs/Environment/betaChecker/index.ts @@ -1,9 +1,7 @@ /** * There's no beta build in non native - * - * @returns {Promise} */ -function isBetaBuild() { +function isBetaBuild(): Promise { return Promise.resolve(false); } diff --git a/src/libs/Environment/getEnvironment/index.native.js b/src/libs/Environment/getEnvironment/index.native.ts similarity index 75% rename from src/libs/Environment/getEnvironment/index.native.js rename to src/libs/Environment/getEnvironment/index.native.ts index 73014c4beffb..1e3333c6a881 100644 --- a/src/libs/Environment/getEnvironment/index.native.js +++ b/src/libs/Environment/getEnvironment/index.native.ts @@ -1,28 +1,25 @@ -import lodashGet from 'lodash/get'; import Config from 'react-native-config'; import betaChecker from '../betaChecker'; import CONST from '../../../CONST'; -let environment = null; +let environment: string | null = null; /** * Returns a promise that resolves with the current environment string value - * - * @returns {Promise} */ -function getEnvironment() { +function getEnvironment(): Promise { return new Promise((resolve) => { // If we've already set the environment, use the current value if (environment) { return resolve(environment); } - if (lodashGet(Config, 'ENVIRONMENT', CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.DEV) { + if ((Config?.ENVIRONMENT ?? CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.DEV) { environment = CONST.ENVIRONMENT.DEV; return resolve(environment); } - if (lodashGet(Config, 'ENVIRONMENT', CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.ADHOC) { + if ((Config?.ENVIRONMENT ?? CONST.ENVIRONMENT.DEV) === CONST.ENVIRONMENT.ADHOC) { environment = CONST.ENVIRONMENT.ADHOC; return resolve(environment); } diff --git a/src/libs/Environment/getEnvironment/index.js b/src/libs/Environment/getEnvironment/index.ts similarity index 53% rename from src/libs/Environment/getEnvironment/index.js rename to src/libs/Environment/getEnvironment/index.ts index a987678d6a6e..2c27be5fc471 100644 --- a/src/libs/Environment/getEnvironment/index.js +++ b/src/libs/Environment/getEnvironment/index.ts @@ -1,14 +1,11 @@ -import lodashGet from 'lodash/get'; import Config from 'react-native-config'; import CONST from '../../../CONST'; /** * Returns a promise that resolves with the current environment string value - * - * @returns {Promise} */ -function getEnvironment() { - return Promise.resolve(lodashGet(Config, 'ENVIRONMENT', CONST.ENVIRONMENT.DEV)); +function getEnvironment(): Promise { + return Promise.resolve(Config?.ENVIRONMENT ?? CONST.ENVIRONMENT.DEV); } export default getEnvironment; From a27b365ec21320343fd4a9921e17ebcf543f9d29 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 2 Oct 2023 09:52:48 +0700 Subject: [PATCH 012/128] fix clicking back button bring back the workspace --- src/libs/actions/App.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index b8be35aa1919..a493dd9b74d9 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -325,9 +325,11 @@ function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = fal } if (shouldNavigateToAdminChat) { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID)); + Navigation.dismissModal(adminsChatReportID); } - + }) + .then(() => Navigation.isNavigationReady()) + .then(() => { Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); }) .then(endSignOnTransition); From a803a71b9ecd22bb274020655a72bde5a76012d2 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 2 Oct 2023 18:55:58 +0700 Subject: [PATCH 013/128] fix refactor logic then --- src/libs/actions/App.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index a493dd9b74d9..5c9a0c2a8628 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -327,8 +327,8 @@ function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = fal if (shouldNavigateToAdminChat) { Navigation.dismissModal(adminsChatReportID); } + return Navigation.isNavigationReady(); }) - .then(() => Navigation.isNavigationReady()) .then(() => { Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); }) From 59a32831104a465c7386dfc1d5090af93f61570a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 2 Oct 2023 16:24:36 +0200 Subject: [PATCH 014/128] review changes --- src/libs/SelectionScraper/index.ts | 36 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index 52fe69fcb75e..4b679734b3a0 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -14,9 +14,11 @@ const tagAttribute = 'data-testid'; */ const getHTMLOfSelection = (): string => { // If browser doesn't support Selection API, return an empty string. + if (!window.getSelection) { + return ''; + } const selection = window.getSelection(); - - if (!selection || !window.getSelection) { + if (!selection) { return ''; } @@ -66,8 +68,8 @@ const getHTMLOfSelection = (): string => { // and finally commonAncestorContainer.parentNode.closest('data-testid') is targeted dom. if (range.commonAncestorContainer instanceof HTMLElement) { parent = range.commonAncestorContainer.closest(`[${tagAttribute}]`); - } else if (range.commonAncestorContainer.parentNode) { - parent = (range.commonAncestorContainer.parentNode as HTMLElement).closest(`[${tagAttribute}]`); + } else { + parent = (range.commonAncestorContainer.parentNode as HTMLElement | null)?.closest(`[${tagAttribute}]`) ?? null; } // Keep traversing up to clone all parents with 'data-testid' attribute. @@ -76,7 +78,7 @@ const getHTMLOfSelection = (): string => { cloned.appendChild(child); child = cloned as DocumentFragment; - parent = (parent.parentNode as HTMLElement).closest(`[${tagAttribute}]`); + parent = (parent.parentNode as HTMLElement | null)?.closest(`[${tagAttribute}]`) ?? null; } div.appendChild(child); @@ -100,16 +102,21 @@ const getHTMLOfSelection = (): string => { * Clears all attributes from dom elements */ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { + // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. + const domDataNode = dom as DataNode; + let data = ''; + if (dom.type.toString() === 'text' && domDataNode.data) { + data = Str.htmlEncode(domDataNode.data); + return { + ...dom, + data, + } as DataNode; + } + const domElement = dom as Element; let domName = domElement.name; let domChildren: Node[] = []; const domAttribs: Element['attribs'] = {}; - let data = ''; - - // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. - if (dom.type.toString() === 'text') { - data = Str.htmlEncode((dom as DataNode).data); - } // We are skipping elements which has html and body in data-testid, since ExpensiMark can't parse it. Also this data // has no meaning for us. @@ -132,13 +139,6 @@ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { domChildren = domElement.children.map((c) => replaceNodes(c, isChildOfEditorElement || !!domElement.attribs?.[tagAttribute])); } - if (data) { - return { - ...dom, - data, - } as DataNode; - } - return { ...dom, name: domName, From 4fe4ff020c80b21bcca6b00131fd2e553fb55075 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Tue, 3 Oct 2023 00:17:04 +0700 Subject: [PATCH 015/128] fix handle case create workspace without openning modal --- src/libs/actions/App.js | 17 +++++++++++++++-- .../FloatingActionButtonAndPopover.js | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 5c9a0c2a8628..fbea58b17efe 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -313,8 +313,17 @@ function endSignOnTransition() { * @param {String} [policyName] Optional, custom policy name we will use for created workspace * @param {Boolean} [transitionFromOldDot] Optional, if the user is transitioning from old dot * @param {Boolean} [shouldNavigateToAdminChat] Optional, navigate to the #admin room after creation + * @param {Boolean} [isThereModalToDismiss] Optional, if there is a modal to dismiss + */ -function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', transitionFromOldDot = false, shouldNavigateToAdminChat = true) { +function createWorkspaceAndNavigateToIt( + policyOwnerEmail = '', + makeMeAdmin = false, + policyName = '', + transitionFromOldDot = false, + shouldNavigateToAdminChat = true, + isThereModalToDismiss = true, +) { const policyID = Policy.generatePolicyID(); const adminsChatReportID = Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); Navigation.isNavigationReady() @@ -325,7 +334,11 @@ function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = fal } if (shouldNavigateToAdminChat) { - Navigation.dismissModal(adminsChatReportID); + if (isThereModalToDismiss) { + Navigation.dismissModal(adminsChatReportID); + } else { + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID)); + } } return Navigation.isNavigationReady(); }) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index e9ede2c9a89a..bf703715848f 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -216,7 +216,7 @@ function FloatingActionButtonAndPopover(props) { iconHeight: 40, text: props.translate('workspace.new.newWorkspace'), description: props.translate('workspace.new.getTheExpensifyCardAndMore'), - onSelected: () => interceptAnonymousUser(() => App.createWorkspaceAndNavigateToIt('', false, '', false, !props.isSmallScreenWidth)), + onSelected: () => interceptAnonymousUser(() => App.createWorkspaceAndNavigateToIt('', false, '', false, !props.isSmallScreenWidth, false)), }, ] : []), From a269b40cf59459fb5cce0edf5aba6c3f89c3d122 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Tue, 3 Oct 2023 07:44:02 -0400 Subject: [PATCH 016/128] update help site to use new https dev --- docs/_includes/CONST.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_includes/CONST.html b/docs/_includes/CONST.html index 4b87f87931d5..af6a14a78331 100644 --- a/docs/_includes/CONST.html +++ b/docs/_includes/CONST.html @@ -1,7 +1,7 @@ {% if jekyll.environment == "production" %} {% assign MAIN_SITE_URL = "https://new.expensify.com" %} {% else %} - {% assign MAIN_SITE_URL = "http://localhost:8082" %} + {% assign MAIN_SITE_URL = "https://new.expensify.com.dev:8082" %} {% endif %} {% capture CONCIERGE_CHAT_URL %}{{MAIN_SITE_URL}}/concierge{% endcapture %} From 94107850a394e68f2edf933013535fcdc6f3581e Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Tue, 3 Oct 2023 07:44:21 -0400 Subject: [PATCH 017/128] add https url to nav --- src/libs/Navigation/linkingConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 533dbf51633a..1e695fa9dcee 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -4,7 +4,7 @@ import CONST from '../../CONST'; import NAVIGATORS from '../../NAVIGATORS'; export default { - prefixes: ['new-expensify://', 'https://www.expensify.cash', 'https://staging.expensify.cash', 'http://localhost', CONST.NEW_EXPENSIFY_URL, CONST.STAGING_NEW_EXPENSIFY_URL], + prefixes: ['new-expensify://', 'https://www.expensify.cash', 'https://staging.expensify.cash', 'https://new.expensify.com.dev', CONST.NEW_EXPENSIFY_URL, CONST.STAGING_NEW_EXPENSIFY_URL], config: { initialRouteName: SCREENS.HOME, screens: { From e8ebe3bc9ffa24480e5417c7c817b47dcf94ee3a Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Tue, 3 Oct 2023 07:44:34 -0400 Subject: [PATCH 018/128] change additional refs to https dev --- contributingGuides/APPLE_GOOGLE_SIGNIN.md | 4 ++-- desktop/main.js | 4 ++-- desktop/start.js | 2 +- src/CONST.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/contributingGuides/APPLE_GOOGLE_SIGNIN.md b/contributingGuides/APPLE_GOOGLE_SIGNIN.md index 9032a99dfbbd..3a1feac073db 100644 --- a/contributingGuides/APPLE_GOOGLE_SIGNIN.md +++ b/contributingGuides/APPLE_GOOGLE_SIGNIN.md @@ -161,10 +161,10 @@ function beginAppleSignIn(idToken) { You can use any SSH tunneling service that allows you to configure custom subdomains so that we have a consistent address to use. We'll use ngrok in these examples, but ngrok requires a paid account for this. If you need a free option, try serveo.net. -After you've set ngrok up to be able to run on your machine (requires configuring a key with the command line tool, instructions provided by the ngrok website after you create an account), test hosting the web app on a custom subdomain. This example assumes the development web app is running at `localhost:8082`: +After you've set ngrok up to be able to run on your machine (requires configuring a key with the command line tool, instructions provided by the ngrok website after you create an account), test hosting the web app on a custom subdomain. This example assumes the development web app is running at `new.expensify.com.dev:8082`: ``` -ngrok http 8082 --host-header="localhost:8082" --subdomain=mysubdomain +ngrok http 8082 --host-header="new.expensify.com.dev:8082" --subdomain=mysubdomain ``` The `--host-header` flag is there to avoid webpack errors with header validation. In addition, add `allowedHosts: 'all'` to the dev server config in `webpack.dev.js`: diff --git a/desktop/main.js b/desktop/main.js index 5e184d529afd..4b43ff128f65 100644 --- a/desktop/main.js +++ b/desktop/main.js @@ -85,7 +85,7 @@ _.assign(console, log.functions); // until it detects that it has been upgraded to the correct version. const EXPECTED_UPDATE_VERSION_FLAG = '--expected-update-version'; -const APP_DOMAIN = __DEV__ ? `http://localhost:${port}` : 'app://-'; +const APP_DOMAIN = __DEV__ ? `https://new.expensify.com.dev:${port}` : 'app://-'; let expectedUpdateVersion; for (let i = 0; i < process.argv.length; i++) { @@ -221,7 +221,7 @@ const mainWindow = () => { let deeplinkUrl; let browserWindow; - const loadURL = __DEV__ ? (win) => win.loadURL(`http://localhost:${port}`) : serve({directory: `${__dirname}/www`}); + const loadURL = __DEV__ ? (win) => win.loadURL(`https://new.expensify.com.dev:${port}`) : serve({directory: `${__dirname}/www`}); // Prod and staging set the icon in the electron-builder config, so only update it here for dev if (__DEV__) { diff --git a/desktop/start.js b/desktop/start.js index d9ec59b71c83..a9bb5a2d588d 100644 --- a/desktop/start.js +++ b/desktop/start.js @@ -32,7 +32,7 @@ portfinder env, }, { - command: `wait-port localhost:${port} && npx electronmon ./desktop/dev.js`, + command: `wait-port new.expensify.com.dev:${port} && npx electronmon ./desktop/dev.js`, name: 'Electron', prefixColor: 'cyan.dim', env, diff --git a/src/CONST.ts b/src/CONST.ts index dbe47c6ed1a7..c8e6fcc65e20 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -448,7 +448,7 @@ const CONST = { ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/', // Use Environment.getEnvironmentURL to get the complete URL with port number - DEV_NEW_EXPENSIFY_URL: 'http://localhost:', + DEV_NEW_EXPENSIFY_URL: 'https://new.expensify.com.dev:', SIGN_IN_FORM_WIDTH: 300, From 89173ee79f3c10f48de8d5449e45b843bf2019aa Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Tue, 3 Oct 2023 20:36:35 +0200 Subject: [PATCH 019/128] Create types for environment urls keys --- src/libs/Environment/Environment.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libs/Environment/Environment.ts b/src/libs/Environment/Environment.ts index f14e21eac90d..b201fd5be439 100644 --- a/src/libs/Environment/Environment.ts +++ b/src/libs/Environment/Environment.ts @@ -17,6 +17,9 @@ const OLDDOT_ENVIRONMENT_URLS = { [CONST.ENVIRONMENT.ADHOC]: CONST.STAGING_EXPENSIFY_URL, }; +type EnvironmentUrlsKeys = keyof typeof ENVIRONMENT_URLS; +type OldDotEnvironmentUrlsKeys = keyof typeof OLDDOT_ENVIRONMENT_URLS; + /** * Are we running the app in development? */ @@ -36,7 +39,7 @@ function isInternalTestBuild(): boolean { */ function getEnvironmentURL(): Promise { return new Promise((resolve) => { - getEnvironment().then((environment) => resolve(ENVIRONMENT_URLS[environment as keyof typeof ENVIRONMENT_URLS])); + getEnvironment().then((environment) => resolve(ENVIRONMENT_URLS[environment as EnvironmentUrlsKeys])); }); } @@ -44,7 +47,7 @@ function getEnvironmentURL(): Promise { * Get the corresponding oldDot URL based on the environment we are in */ function getOldDotEnvironmentURL(): Promise { - return getEnvironment().then((environment) => OLDDOT_ENVIRONMENT_URLS[environment as keyof typeof OLDDOT_ENVIRONMENT_URLS]); + return getEnvironment().then((environment) => OLDDOT_ENVIRONMENT_URLS[environment as OldDotEnvironmentUrlsKeys]); } export {getEnvironment, isInternalTestBuild, isDevelopment, getEnvironmentURL, getOldDotEnvironmentURL}; From 0be46040ab60b2cd4b3ed58ff106e0dba98d3a4f Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Tue, 3 Oct 2023 21:52:50 -0400 Subject: [PATCH 020/128] fix unit test --- tests/unit/ReportUtilsTest.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index 24397a04a0e9..9ddf9b93f8d0 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -503,8 +503,7 @@ describe('ReportUtils', () => { expect(ReportUtils.getReportIDFromLink('new-expensify://r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://www.expensify.cash/r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://staging.new.expensify.com/r/75431276')).toBe('75431276'); - expect(ReportUtils.getReportIDFromLink('http://localhost/r/75431276')).toBe('75431276'); - expect(ReportUtils.getReportIDFromLink('http://localhost:8080/r/75431276')).toBe('75431276'); + expect(ReportUtils.getReportIDFromLink('https://new.expensify.com.dev/r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://staging.expensify.cash/r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://new.expensify.com/r/75431276')).toBe('75431276'); }); From 9b266fae39474f474ebd21dd08bc38fb342999a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Wed, 4 Oct 2023 10:47:09 +0200 Subject: [PATCH 021/128] fix replaceNodes function --- src/libs/SelectionScraper/index.ts | 59 +++++++++++++++--------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index 4b679734b3a0..d865cd75e850 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -100,51 +100,50 @@ const getHTMLOfSelection = (): string => { /** * Clears all attributes from dom elements + * @param dom - dom htmlparser2 dom representation */ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { - // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. - const domDataNode = dom as DataNode; - let data = ''; - if (dom.type.toString() === 'text' && domDataNode.data) { - data = Str.htmlEncode(domDataNode.data); - return { - ...dom, - data, - } as DataNode; - } - - const domElement = dom as Element; - let domName = domElement.name; + let domName; let domChildren: Node[] = []; const domAttribs: Element['attribs'] = {}; + let data = ''; - // We are skipping elements which has html and body in data-testid, since ExpensiMark can't parse it. Also this data - // has no meaning for us. - if (domElement.attribs?.[tagAttribute]) { - if (!elementsWillBeSkipped.includes(domElement.attribs[tagAttribute])) { - domName = domElement.attribs[tagAttribute]; - } - } else if (domElement.name === 'div' && domElement.children.length === 1 && isChildOfEditorElement) { - // We are excluding divs that are children of our editor element and have only one child to prevent - // additional newlines from being added in the HTML to Markdown conversion process. - return replaceNodes(domElement.children[0], isChildOfEditorElement); + // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. + if (dom.type.toString() === 'text' && dom instanceof DataNode) { + data = Str.htmlEncode(dom.data); } - // We need to preserve href attribute in order to copy links. - if (domElement.attribs?.href) { - domAttribs.href = domElement.attribs.href; - } + if (dom instanceof Element) { + domName = dom.name; + // We are skipping elements which has html and body in data-testid, since ExpensiMark can't parse it. Also this data + // has no meaning for us. + if (dom.attribs?.[tagAttribute]) { + if (!elementsWillBeSkipped.includes(dom.attribs[tagAttribute])) { + domName = dom.attribs[tagAttribute]; + } + } else if (dom.name === 'div' && dom.children.length === 1 && isChildOfEditorElement) { + // We are excluding divs that are children of our editor element and have only one child to prevent + // additional newlines from being added in the HTML to Markdown conversion process. + return replaceNodes(dom.children[0], isChildOfEditorElement); + } - if (domElement.children) { - domChildren = domElement.children.map((c) => replaceNodes(c, isChildOfEditorElement || !!domElement.attribs?.[tagAttribute])); + // We need to preserve href attribute in order to copy links. + if (dom.attribs?.href) { + domAttribs.href = dom.attribs.href; + } + + if (dom.children) { + domChildren = dom.children.map((c) => replaceNodes(c, isChildOfEditorElement || !!dom.attribs?.[tagAttribute])); + } } return { ...dom, + data, name: domName, attribs: domAttribs, children: domChildren, - } as Element; + } as unknown as Node; }; /** From 772975082c0725c5ac88f20065adb437944ca3b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Wed, 4 Oct 2023 16:21:49 +0200 Subject: [PATCH 022/128] change replaceNodes return object type --- src/libs/SelectionScraper/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index d865cd75e850..0368087b5f38 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -143,7 +143,7 @@ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { name: domName, attribs: domAttribs, children: domChildren, - } as unknown as Node; + } as Element & DataNode; }; /** From 392e320554727161916e4547eb24afd7567a5641 Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Fri, 6 Oct 2023 22:32:14 +0700 Subject: [PATCH 023/128] fix wait for browser history load url after navigate --- src/libs/actions/App.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index fbea58b17efe..753e73947c4e 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -336,14 +336,24 @@ function createWorkspaceAndNavigateToIt( if (shouldNavigateToAdminChat) { if (isThereModalToDismiss) { Navigation.dismissModal(adminsChatReportID); + setTimeout(() => { + Navigation.navigate(ROUTES.SETTINGS); + setTimeout(() => { + Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); + setTimeout(() => { + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); + }, 50); + }, 50); + }, 50); } else { Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID)); + setTimeout(() => { + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); + }, 50); } + } else { + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); } - return Navigation.isNavigationReady(); - }) - .then(() => { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); }) .then(endSignOnTransition); } From f9717fd85f6239df5df5c5b4d446293eb5be0899 Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Sat, 7 Oct 2023 11:43:03 +0530 Subject: [PATCH 024/128] fixed offline jumping behaviour --- src/components/AddressSearch/index.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index fe220d442674..84e009fdc081 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -294,12 +294,14 @@ function AddressSearch(props) { ) } listLoaderComponent={ - - - + props.network.isOffline ? null : ( + + + + ) } renderHeaderComponent={() => !props.value && From 3ebd5f97bdd31d5689ac8a9f75a577c70d1808a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 9 Oct 2023 11:40:09 +0200 Subject: [PATCH 025/128] fix replaceNodes condition --- src/libs/SelectionScraper/index.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index 0368087b5f38..abe9a235fca8 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -111,9 +111,7 @@ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { // Encoding HTML chars '< >' in the text, because any HTML will be removed in stripHTML method. if (dom.type.toString() === 'text' && dom instanceof DataNode) { data = Str.htmlEncode(dom.data); - } - - if (dom instanceof Element) { + } else if (dom instanceof Element) { domName = dom.name; // We are skipping elements which has html and body in data-testid, since ExpensiMark can't parse it. Also this data // has no meaning for us. @@ -135,6 +133,8 @@ const replaceNodes = (dom: Node, isChildOfEditorElement: boolean): Node => { if (dom.children) { domChildren = dom.children.map((c) => replaceNodes(c, isChildOfEditorElement || !!dom.attribs?.[tagAttribute])); } + } else { + throw new Error(`Unknown dom type: ${dom.type}`); } return { From 16608759411ace3d75f90f7f19ccfb5cca1282bc Mon Sep 17 00:00:00 2001 From: Shubham Agrawal Date: Mon, 9 Oct 2023 22:00:50 +0530 Subject: [PATCH 026/128] fix package upstream --- package-lock.json | 14 +++++++------- package.json | 2 +- src/components/AddressSearch/index.js | 14 ++++++-------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index ddebbe8a3832..9539536b7891 100644 --- a/package-lock.json +++ b/package-lock.json @@ -85,7 +85,7 @@ "react-native-fast-image": "^8.6.3", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.12.0", - "react-native-google-places-autocomplete": "2.5.5", + "react-native-google-places-autocomplete": "2.5.6", "react-native-haptic-feedback": "^1.13.0", "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.1.0", @@ -44589,9 +44589,9 @@ } }, "node_modules/react-native-google-places-autocomplete": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/react-native-google-places-autocomplete/-/react-native-google-places-autocomplete-2.5.5.tgz", - "integrity": "sha512-ypqaHYRifcY9q28HkZYExzHMF4Eul+mf3y4dlIlvBj3SgLI2FyrD1mdQoF8A7xwhOWctYs6PsVj3Mg71IVJTTw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/react-native-google-places-autocomplete/-/react-native-google-places-autocomplete-2.5.6.tgz", + "integrity": "sha512-Dy7mFKyEoiNeWPLd7HUkrI/SzJYe7GST55FGtiXzXDoPs05LYHIOCPrT9qFE51COh5X8kgDKm+f7D5aMY/aMbg==", "dependencies": { "lodash.debounce": "^4.0.8", "prop-types": "^15.7.2", @@ -85211,9 +85211,9 @@ } }, "react-native-google-places-autocomplete": { - "version": "2.5.5", - "resolved": "https://registry.npmjs.org/react-native-google-places-autocomplete/-/react-native-google-places-autocomplete-2.5.5.tgz", - "integrity": "sha512-ypqaHYRifcY9q28HkZYExzHMF4Eul+mf3y4dlIlvBj3SgLI2FyrD1mdQoF8A7xwhOWctYs6PsVj3Mg71IVJTTw==", + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/react-native-google-places-autocomplete/-/react-native-google-places-autocomplete-2.5.6.tgz", + "integrity": "sha512-Dy7mFKyEoiNeWPLd7HUkrI/SzJYe7GST55FGtiXzXDoPs05LYHIOCPrT9qFE51COh5X8kgDKm+f7D5aMY/aMbg==", "requires": { "lodash.debounce": "^4.0.8", "prop-types": "^15.7.2", diff --git a/package.json b/package.json index 9a3b9ed3af86..2b97739bc050 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "react-native-fast-image": "^8.6.3", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "2.12.0", - "react-native-google-places-autocomplete": "2.5.5", + "react-native-google-places-autocomplete": "2.5.6", "react-native-haptic-feedback": "^1.13.0", "react-native-image-pan-zoom": "^2.1.12", "react-native-image-picker": "^5.1.0", diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index 84e009fdc081..fe220d442674 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -294,14 +294,12 @@ function AddressSearch(props) { ) } listLoaderComponent={ - props.network.isOffline ? null : ( - - - - ) + + + } renderHeaderComponent={() => !props.value && From e2738d30b5e767e3568e4476fbc6438870c19607 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 11 Oct 2023 12:06:24 +0200 Subject: [PATCH 027/128] Remove assertion --- src/libs/Environment/Environment.ts | 7 ++----- src/libs/Environment/getEnvironment/index.native.ts | 5 +++-- src/libs/Environment/getEnvironment/index.ts | 5 +++-- src/libs/Environment/getEnvironment/types.ts | 6 ++++++ 4 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 src/libs/Environment/getEnvironment/types.ts diff --git a/src/libs/Environment/Environment.ts b/src/libs/Environment/Environment.ts index b201fd5be439..60b83e0a1dfe 100644 --- a/src/libs/Environment/Environment.ts +++ b/src/libs/Environment/Environment.ts @@ -17,9 +17,6 @@ const OLDDOT_ENVIRONMENT_URLS = { [CONST.ENVIRONMENT.ADHOC]: CONST.STAGING_EXPENSIFY_URL, }; -type EnvironmentUrlsKeys = keyof typeof ENVIRONMENT_URLS; -type OldDotEnvironmentUrlsKeys = keyof typeof OLDDOT_ENVIRONMENT_URLS; - /** * Are we running the app in development? */ @@ -39,7 +36,7 @@ function isInternalTestBuild(): boolean { */ function getEnvironmentURL(): Promise { return new Promise((resolve) => { - getEnvironment().then((environment) => resolve(ENVIRONMENT_URLS[environment as EnvironmentUrlsKeys])); + getEnvironment().then((environment) => resolve(ENVIRONMENT_URLS[environment])); }); } @@ -47,7 +44,7 @@ function getEnvironmentURL(): Promise { * Get the corresponding oldDot URL based on the environment we are in */ function getOldDotEnvironmentURL(): Promise { - return getEnvironment().then((environment) => OLDDOT_ENVIRONMENT_URLS[environment as OldDotEnvironmentUrlsKeys]); + return getEnvironment().then((environment) => OLDDOT_ENVIRONMENT_URLS[environment]); } export {getEnvironment, isInternalTestBuild, isDevelopment, getEnvironmentURL, getOldDotEnvironmentURL}; diff --git a/src/libs/Environment/getEnvironment/index.native.ts b/src/libs/Environment/getEnvironment/index.native.ts index 1e3333c6a881..0e3b943b1bd5 100644 --- a/src/libs/Environment/getEnvironment/index.native.ts +++ b/src/libs/Environment/getEnvironment/index.native.ts @@ -1,13 +1,14 @@ import Config from 'react-native-config'; import betaChecker from '../betaChecker'; import CONST from '../../../CONST'; +import Environment from './types'; -let environment: string | null = null; +let environment: Environment | null = null; /** * Returns a promise that resolves with the current environment string value */ -function getEnvironment(): Promise { +function getEnvironment(): Promise { return new Promise((resolve) => { // If we've already set the environment, use the current value if (environment) { diff --git a/src/libs/Environment/getEnvironment/index.ts b/src/libs/Environment/getEnvironment/index.ts index 2c27be5fc471..9a18a997eec6 100644 --- a/src/libs/Environment/getEnvironment/index.ts +++ b/src/libs/Environment/getEnvironment/index.ts @@ -1,11 +1,12 @@ import Config from 'react-native-config'; import CONST from '../../../CONST'; +import Environment from './types'; /** * Returns a promise that resolves with the current environment string value */ -function getEnvironment(): Promise { - return Promise.resolve(Config?.ENVIRONMENT ?? CONST.ENVIRONMENT.DEV); +function getEnvironment(): Promise { + return Promise.resolve((Config?.ENVIRONMENT as Environment) ?? CONST.ENVIRONMENT.DEV); } export default getEnvironment; diff --git a/src/libs/Environment/getEnvironment/types.ts b/src/libs/Environment/getEnvironment/types.ts new file mode 100644 index 000000000000..7cf17af3e0d8 --- /dev/null +++ b/src/libs/Environment/getEnvironment/types.ts @@ -0,0 +1,6 @@ +import {ValueOf} from 'type-fest'; +import CONST from '../../../CONST'; + +type Environment = ValueOf; + +export default Environment; From 598f97f5471915b03bc9e62a94a4ad728a5f8b27 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Wed, 11 Oct 2023 17:01:03 +0200 Subject: [PATCH 028/128] ref: moved useArrowKeyFocusManager to TS --- ...sManager.js => useArrowKeyFocusManager.ts} | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) rename src/hooks/{useArrowKeyFocusManager.js => useArrowKeyFocusManager.ts} (77%) diff --git a/src/hooks/useArrowKeyFocusManager.js b/src/hooks/useArrowKeyFocusManager.ts similarity index 77% rename from src/hooks/useArrowKeyFocusManager.js rename to src/hooks/useArrowKeyFocusManager.ts index 58cecb169249..4f06111df09b 100644 --- a/src/hooks/useArrowKeyFocusManager.js +++ b/src/hooks/useArrowKeyFocusManager.ts @@ -2,19 +2,27 @@ import {useState, useEffect, useCallback, useMemo} from 'react'; import useKeyboardShortcut from './useKeyboardShortcut'; import CONST from '../CONST'; +type Config = { + maxIndex: number; + onFocusedIndexChange?: (index: number) => void; + initialFocusedIndex?: number; + disabledIndexes?: readonly number[]; + shouldExcludeTextAreaNodes?: boolean; + isActive?: boolean; +}; + /** * A hook that makes it easy to use the arrow keys to manage focus of items in a list * * Recommendation: To ensure stability, wrap the `onFocusedIndexChange` function with the useCallback hook before using it with this hook. * - * @param {Object} config - * @param {Number} config.maxIndex โ€“ typically the number of items in your list - * @param {Function} [config.onFocusedIndexChange] โ€“ optional callback to execute when focusedIndex changes - * @param {Number} [config.initialFocusedIndex] โ€“ where to start in the list - * @param {Array} [config.disabledIndexes] โ€“ An array of indexes to disable + skip over - * @param {Boolean} [config.shouldExcludeTextAreaNodes] โ€“ Whether arrow keys should have any effect when a TextArea node is focused - * @param {Boolean} [config.isActive] โ€“ Whether the component is ready and should subscribe to KeyboardShortcut - * @returns {Array} + * @param config + * @param config.maxIndex โ€“ typically the number of items in your list + * @param [config.onFocusedIndexChange] โ€“ optional callback to execute when focusedIndex changes + * @param [config.initialFocusedIndex] โ€“ where to start in the list + * @param [config.disabledIndexes] โ€“ An array of indexes to disable + skip over + * @param [config.shouldExcludeTextAreaNodes] โ€“ Whether arrow keys should have any effect when a TextArea node is focused + * @param [config.isActive] โ€“ Whether the component is ready and should subscribe to KeyboardShortcut */ export default function useArrowKeyFocusManager({ maxIndex, @@ -26,7 +34,7 @@ export default function useArrowKeyFocusManager({ disabledIndexes = CONST.EMPTY_ARRAY, shouldExcludeTextAreaNodes = true, isActive, -}) { +}: Config): [number, (index: number) => void] { const [focusedIndex, setFocusedIndex] = useState(initialFocusedIndex); const arrowConfig = useMemo( () => ({ From cb7efb9b6c9215e96170476572c7203845681683 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Wed, 11 Oct 2023 22:32:34 +0200 Subject: [PATCH 029/128] Add IsBetaBuild type --- src/libs/Environment/betaChecker/index.android.ts | 3 ++- src/libs/Environment/betaChecker/index.ios.ts | 3 ++- src/libs/Environment/betaChecker/index.ts | 4 +++- src/libs/Environment/betaChecker/types.ts | 3 +++ 4 files changed, 10 insertions(+), 3 deletions(-) create mode 100644 src/libs/Environment/betaChecker/types.ts diff --git a/src/libs/Environment/betaChecker/index.android.ts b/src/libs/Environment/betaChecker/index.android.ts index 8b3afed3b2f3..e33b9c7feb6e 100644 --- a/src/libs/Environment/betaChecker/index.android.ts +++ b/src/libs/Environment/betaChecker/index.android.ts @@ -4,6 +4,7 @@ import CONST from '../../../CONST'; import pkg from '../../../../package.json'; import ONYXKEYS from '../../../ONYXKEYS'; import * as AppUpdate from '../../actions/AppUpdate'; +import IsBetaBuild from './types'; let isLastSavedBeta = false; Onyx.connect({ @@ -19,7 +20,7 @@ Onyx.connect({ /** * Check the GitHub releases to see if the current build is a beta build or production build */ -function isBetaBuild(): Promise { +function isBetaBuild(): IsBetaBuild { return new Promise((resolve) => { fetch(CONST.GITHUB_RELEASE_URL) .then((res) => res.json()) diff --git a/src/libs/Environment/betaChecker/index.ios.ts b/src/libs/Environment/betaChecker/index.ios.ts index 2d6079e30a1c..0d901fc4b003 100644 --- a/src/libs/Environment/betaChecker/index.ios.ts +++ b/src/libs/Environment/betaChecker/index.ios.ts @@ -1,9 +1,10 @@ import {NativeModules} from 'react-native'; +import IsBetaBuild from './types'; /** * Check to see if the build is staging (TestFlight) or production */ -function isBetaBuild(): Promise { +function isBetaBuild(): IsBetaBuild { return new Promise((resolve) => { NativeModules.EnvironmentChecker.isBeta().then((isBeta: boolean) => { resolve(isBeta); diff --git a/src/libs/Environment/betaChecker/index.ts b/src/libs/Environment/betaChecker/index.ts index cda7c297624f..541a3120ccce 100644 --- a/src/libs/Environment/betaChecker/index.ts +++ b/src/libs/Environment/betaChecker/index.ts @@ -1,7 +1,9 @@ +import IsBetaBuild from './types'; + /** * There's no beta build in non native */ -function isBetaBuild(): Promise { +function isBetaBuild(): IsBetaBuild { return Promise.resolve(false); } diff --git a/src/libs/Environment/betaChecker/types.ts b/src/libs/Environment/betaChecker/types.ts new file mode 100644 index 000000000000..61ce4bc9cec4 --- /dev/null +++ b/src/libs/Environment/betaChecker/types.ts @@ -0,0 +1,3 @@ +type IsBetaBuild = Promise; + +export default IsBetaBuild; From 1d6bb1d14cff3dd029868a0a7c8ee14ae78c527b Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Thu, 12 Oct 2023 11:18:33 -0400 Subject: [PATCH 030/128] use server instead of https config --- config/webpack/webpack.dev.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index 1e7074b16277..dcca84ce5e9d 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -45,9 +45,12 @@ module.exports = (env = {}) => historyApiFallback: true, port, host: 'new.expensify.com.dev', - https: { - key: path.join(__dirname, 'key.pem'), - cert: path.join(__dirname, 'certificate.pem'), + server: { + type: 'https', + options: { + key: path.join(__dirname, 'key.pem'), + cert: path.join(__dirname, 'certificate.pem'), + }, }, }, plugins: [ From c102c52abc79a22646509e3486a80da647645340 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Fri, 13 Oct 2023 15:03:43 +0200 Subject: [PATCH 031/128] fix: resolve comment --- src/hooks/useArrowKeyFocusManager.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/hooks/useArrowKeyFocusManager.ts b/src/hooks/useArrowKeyFocusManager.ts index 4f06111df09b..5746700b3c64 100644 --- a/src/hooks/useArrowKeyFocusManager.ts +++ b/src/hooks/useArrowKeyFocusManager.ts @@ -11,6 +11,8 @@ type Config = { isActive?: boolean; }; +type UseArrowKeyFocusManager = [number, (index: number) => void]; + /** * A hook that makes it easy to use the arrow keys to manage focus of items in a list * @@ -34,7 +36,7 @@ export default function useArrowKeyFocusManager({ disabledIndexes = CONST.EMPTY_ARRAY, shouldExcludeTextAreaNodes = true, isActive, -}: Config): [number, (index: number) => void] { +}: Config): UseArrowKeyFocusManager { const [focusedIndex, setFocusedIndex] = useState(initialFocusedIndex); const arrowConfig = useMemo( () => ({ From 86e1ef176839afdd8df5c625164b9e9c049266d9 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Fri, 13 Oct 2023 15:16:02 +0200 Subject: [PATCH 032/128] Resolve typecheck errors --- src/libs/ApiUtils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/ApiUtils.ts b/src/libs/ApiUtils.ts index 87a251ccb086..54c7689dc4fb 100644 --- a/src/libs/ApiUtils.ts +++ b/src/libs/ApiUtils.ts @@ -1,3 +1,4 @@ +import {ValueOf} from 'type-fest'; import Onyx from 'react-native-onyx'; import ONYXKEYS from '../ONYXKEYS'; import CONFIG from '../CONFIG'; @@ -8,7 +9,7 @@ import {Request} from '../types/onyx'; // To avoid rebuilding native apps, native apps use production config for both staging and prod // We use the async environment check because it works on all platforms -let ENV_NAME = CONST.ENVIRONMENT.PRODUCTION; +let ENV_NAME: ValueOf = CONST.ENVIRONMENT.PRODUCTION; let shouldUseStagingServer = false; Environment.getEnvironment().then((envName) => { ENV_NAME = envName; From e48b32e09b52d18d944c5d77a86cc12c2dc658f2 Mon Sep 17 00:00:00 2001 From: Jakub Butkiewicz Date: Mon, 16 Oct 2023 12:32:43 +0200 Subject: [PATCH 033/128] fix: resolved comment --- src/hooks/useArrowKeyFocusManager.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hooks/useArrowKeyFocusManager.ts b/src/hooks/useArrowKeyFocusManager.ts index 5746700b3c64..b2d1af1d659d 100644 --- a/src/hooks/useArrowKeyFocusManager.ts +++ b/src/hooks/useArrowKeyFocusManager.ts @@ -18,7 +18,6 @@ type UseArrowKeyFocusManager = [number, (index: number) => void]; * * Recommendation: To ensure stability, wrap the `onFocusedIndexChange` function with the useCallback hook before using it with this hook. * - * @param config * @param config.maxIndex โ€“ typically the number of items in your list * @param [config.onFocusedIndexChange] โ€“ optional callback to execute when focusedIndex changes * @param [config.initialFocusedIndex] โ€“ where to start in the list From e733f372f4d63779b349439d821fd843317d743a Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Tue, 17 Oct 2023 20:59:42 +0900 Subject: [PATCH 034/128] docs: add instructions for moving certificates --- README.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/README.md b/README.md index 6b5f96de6b72..17c4f83e2113 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ #### Table of Contents * [Local Development](#local-development) +* [Testing on browsers on simulators and emulators](#testing-on-browsers-on-simulators-and-emulators) * [Running The Tests](#running-the-tests) * [Debugging](#debugging) * [App Structure and Conventions](#app-structure-and-conventions) @@ -113,6 +114,47 @@ variables referenced here get updated since your local `.env` file is ignored. ---- +# Testing on browsers on simulators and emulators + +The development server is reached through the HTTPS protocol, and any client that access the development server needs a certificate. + +You create this certificate by following the instructions in [`Configuring HTTPS`](#configuring-https) of this readme. When accessing the website served from the development server on browsers on iOS simulator or Android emulator, these virtual devices need to have the same certificate installed. Follow the steps below to install to do so. + +#### Pre-requisite for Android flow +1. Open any emulator using Android Studio +2. Use `adb push "$(mkcert -CAROOT)/rootCA.pem" /storage/emulated/0/Download/` to push certificate to install in Download folder. +3. Install the certificate as CA certificate from the settings. +4. Close the emulator. + +Note - If you want to run app on `https://127.0.0.1:8082`, then just install the certificate and use `adb reverse tcp:8082 tcp:8082` on every startup. + +#### Android Flow +1. Run `npm run setupNewDotWebForEmulators android` +2. Select the emulator you want to run if prompted. (If single emulator is available, then it will open automatically) +3. Let the script execute till the message `๐ŸŽ‰ Done!`. +4. Check the emulator is closed. + +Note - If you want to run app on `https://new.expensify.com.dev:8082`, then just do the Android flow and use `npm run startAndroidEmulator` to start the Android Emulator every time (It will configure the emulator). + + +Possible Scenario: +1. It may run the second flow on a new device, then to check first flow just run the flow again and select the same device. +2. It may fail to root with error `adbd cannot run as root in production builds`, then it will point to https://stackoverflow.com/a/45668555 in the console. + +#### iOS Flow +1. Run `npm run setupNewDotWebForEmulators ios` +2. Select the emulator you want to run if prompted. (If single emulator is available, then it will open automatically) +3. Let the script execute till the message `๐ŸŽ‰ Done!`. +4. Check the emulator is closed. + +#### All Flow +1. Run `npm run setupNewDotWebForEmulators all` or `npm run setupNewDotWebForEmulators` +2. Check if the iOS flow runs first and then Android flow runs. +3. Let the script execute till the message `๐ŸŽ‰ Done!`. +4. Check the emulator is closed. + +---- + # Running the tests ## Unit tests Unit tests are valuable when you want to test one component. They should be short, fast, and ideally only test one thing. From 6aeab2f7b1c996634fc7c20bc24b661dee8bd0f4 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 18 Oct 2023 21:53:59 +0900 Subject: [PATCH 035/128] docs: update readme --- README.md | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 17c4f83e2113..d96bafd85061 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ You create this certificate by following the instructions in [`Configuring HTTPS #### Pre-requisite for Android flow 1. Open any emulator using Android Studio 2. Use `adb push "$(mkcert -CAROOT)/rootCA.pem" /storage/emulated/0/Download/` to push certificate to install in Download folder. -3. Install the certificate as CA certificate from the settings. +3. Install the certificate as CA certificate from the settings. On the Android emulator, this option can be found in Settings > Security > Encryption & Credentials > Install a certificate > CA certificate. 4. Close the emulator. Note - If you want to run app on `https://127.0.0.1:8082`, then just install the certificate and use `adb reverse tcp:8082 tcp:8082` on every startup. @@ -132,26 +132,22 @@ Note - If you want to run app on `https://127.0.0.1:8082`, then just install the 1. Run `npm run setupNewDotWebForEmulators android` 2. Select the emulator you want to run if prompted. (If single emulator is available, then it will open automatically) 3. Let the script execute till the message `๐ŸŽ‰ Done!`. -4. Check the emulator is closed. Note - If you want to run app on `https://new.expensify.com.dev:8082`, then just do the Android flow and use `npm run startAndroidEmulator` to start the Android Emulator every time (It will configure the emulator). Possible Scenario: -1. It may run the second flow on a new device, then to check first flow just run the flow again and select the same device. -2. It may fail to root with error `adbd cannot run as root in production builds`, then it will point to https://stackoverflow.com/a/45668555 in the console. +The flow may fail to root with error `adbd cannot run as root in production builds`. In this case, please refer to https://stackoverflow.com/a/45668555. Or use `https://127.0.0.1:8082` for less hassle. #### iOS Flow 1. Run `npm run setupNewDotWebForEmulators ios` 2. Select the emulator you want to run if prompted. (If single emulator is available, then it will open automatically) 3. Let the script execute till the message `๐ŸŽ‰ Done!`. -4. Check the emulator is closed. #### All Flow 1. Run `npm run setupNewDotWebForEmulators all` or `npm run setupNewDotWebForEmulators` 2. Check if the iOS flow runs first and then Android flow runs. 3. Let the script execute till the message `๐ŸŽ‰ Done!`. -4. Check the emulator is closed. ---- From a2a2fda4523474244b7b8dbfe351eed459973e23 Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 18 Oct 2023 07:10:35 -0700 Subject: [PATCH 036/128] fix typo Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d96bafd85061..b217690f37ed 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ variables referenced here get updated since your local `.env` file is ignored. ---- -# Testing on browsers on simulators and emulators +# Testing on browsers in simulators and emulators The development server is reached through the HTTPS protocol, and any client that access the development server needs a certificate. From 512d08434510ce8f6a4978e94796528b330d84bf Mon Sep 17 00:00:00 2001 From: Hayata Suenaga Date: Wed, 18 Oct 2023 07:11:19 -0700 Subject: [PATCH 037/128] fix typo Co-authored-by: Vit Horacek <36083550+mountiny@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b217690f37ed..48c4cb03baf0 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ variables referenced here get updated since your local `.env` file is ignored. The development server is reached through the HTTPS protocol, and any client that access the development server needs a certificate. -You create this certificate by following the instructions in [`Configuring HTTPS`](#configuring-https) of this readme. When accessing the website served from the development server on browsers on iOS simulator or Android emulator, these virtual devices need to have the same certificate installed. Follow the steps below to install to do so. +You create this certificate by following the instructions in [`Configuring HTTPS`](#configuring-https) of this readme. When accessing the website served from the development server on browsers in iOS simulator or Android emulator, these virtual devices need to have the same certificate installed. Follow the steps below to install them. #### Pre-requisite for Android flow 1. Open any emulator using Android Studio From 3d0b045c01d35b7759d2dcb72ea96a791c07fa6c Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Wed, 18 Oct 2023 10:53:51 -0600 Subject: [PATCH 038/128] Rename shouldDisableWriteActions to canUserPerformWriteAction --- src/libs/ReportUtils.js | 7 ++++--- src/libs/SidebarUtils.js | 2 +- src/pages/home/report/ReportActionsList.js | 2 +- src/pages/home/report/ReportFooter.js | 2 +- src/pages/iou/steps/NewRequestAmountPage.js | 2 +- src/pages/tasks/TaskShareDestinationSelectorModal.js | 2 +- tests/unit/OptionsListUtilsTest.js | 4 ++-- 7 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 4e351d2dc5e3..7a376c59e6a3 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3386,7 +3386,7 @@ function parseReportRouteParams(route) { parsingRoute = parsingRoute.slice(1); } - if (!parsingRoute.startsWith(Url.addTrailingForwardSlash('r'))) { + if (!parsingRoute.startsWith(Url.addTrailingForwardSlash(ROUTES.REPORT))) { return {reportID: '', isSubReportPageRoute: false}; } @@ -3662,9 +3662,10 @@ function getAddWorkspaceRoomOrChatReportErrors(report) { * @param {Object} report * @returns {Boolean} */ -function shouldDisableWriteActions(report) { +function canUserPerformWriteAction(report) { const reportErrors = getAddWorkspaceRoomOrChatReportErrors(report); return isArchivedRoom(report) || !_.isEmpty(reportErrors) || !isAllowedToComment(report) || isAnonymousUser; + return !isArchivedRoom(report) && _.isEmpty(reportErrors) && isAllowedToComment(report) && !isAnonymousUser; } /** @@ -4057,7 +4058,7 @@ export { getRootParentReport, getReportPreviewMessage, getModifiedExpenseMessage, - shouldDisableWriteActions, + canUserPerformWriteAction, getOriginalReportID, canAccessReport, getAddWorkspaceRoomOrChatReportErrors, diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index dd6db33902fb..9018ed1ddd80 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -305,7 +305,7 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, result.parentReportID = report.parentReportID || null; result.isWaitingOnBankAccount = report.isWaitingOnBankAccount; result.notificationPreference = report.notificationPreference || null; - result.isAllowedToComment = !ReportUtils.shouldDisableWriteActions(report); + result.isAllowedToComment = !ReportUtils.canUserPerformWriteAction(report); const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; const subtitle = ReportUtils.getChatRoomSubtitle(report); diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index c673c06470f8..e986c7b53528 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -334,7 +334,7 @@ function ReportActionsList({ // Native mobile does not render updates flatlist the changes even though component did update called. // To notify there something changes we can use extraData prop to flatlist const extraData = [isSmallScreenWidth ? currentUnreadMarker : undefined, ReportUtils.isArchivedRoom(report)]; - const hideComposer = ReportUtils.shouldDisableWriteActions(report); + const hideComposer = ReportUtils.canUserPerformWriteAction(report); const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(personalDetailsList, report, currentUserPersonalDetails.accountID) && !isComposerFullSize; const renderFooter = useCallback(() => { diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index 2237e6448504..c96824770f07 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -70,7 +70,7 @@ function ReportFooter(props) { const isAnonymousUser = Session.isAnonymousUser(); const isSmallSizeLayout = props.windowWidth - (props.isSmallScreenWidth ? 0 : variables.sideBarWidth) < variables.anonymousReportFooterBreakpoint; - const hideComposer = ReportUtils.shouldDisableWriteActions(props.report); + const hideComposer = ReportUtils.canUserPerformWriteAction(props.report); return ( <> diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index ae319f5a73bb..dda52352e015 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -85,7 +85,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { // Check and dismiss modal useEffect(() => { - if (!ReportUtils.shouldDisableWriteActions(report)) { + if (!ReportUtils.canUserPerformWriteAction(report)) { return; } Navigation.dismissModal(reportID); diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.js b/src/pages/tasks/TaskShareDestinationSelectorModal.js index 2fc8f0eab014..f1cd009d197d 100644 --- a/src/pages/tasks/TaskShareDestinationSelectorModal.js +++ b/src/pages/tasks/TaskShareDestinationSelectorModal.js @@ -52,7 +52,7 @@ function TaskShareDestinationSelectorModal(props) { const reports = {}; _.keys(props.reports).forEach((reportKey) => { if ( - ReportUtils.shouldDisableWriteActions(props.reports[reportKey]) || + ReportUtils.canUserPerformWriteAction(props.reports[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(props.reports[reportKey]) || ReportUtils.isCanceledTaskReport(props.reports[reportKey]) ) { diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index eda743f85aa2..0032f6a1ad42 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -590,7 +590,7 @@ describe('OptionsListUtils', () => { // Filter current REPORTS as we do in the component, before getting share destination options const filteredReports = {}; _.keys(REPORTS).forEach((reportKey) => { - if (ReportUtils.shouldDisableWriteActions(REPORTS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS[reportKey])) { + if (ReportUtils.canUserPerformWriteAction(REPORTS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS[reportKey])) { return; } filteredReports[reportKey] = REPORTS[reportKey]; @@ -617,7 +617,7 @@ describe('OptionsListUtils', () => { // Filter current REPORTS_WITH_WORKSPACE_ROOMS as we do in the component, before getting share destination options const filteredReportsWithWorkspaceRooms = {}; _.keys(REPORTS_WITH_WORKSPACE_ROOMS).forEach((reportKey) => { - if (ReportUtils.shouldDisableWriteActions(REPORTS_WITH_WORKSPACE_ROOMS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS_WITH_WORKSPACE_ROOMS[reportKey])) { + if (ReportUtils.canUserPerformWriteAction(REPORTS_WITH_WORKSPACE_ROOMS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS_WITH_WORKSPACE_ROOMS[reportKey])) { return; } filteredReportsWithWorkspaceRooms[reportKey] = REPORTS_WITH_WORKSPACE_ROOMS[reportKey]; From b4d942fc7d23c314ec7e6efab99c19073cce560f Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 19 Oct 2023 10:46:56 +0200 Subject: [PATCH 039/128] WIP --- src/pages/settings/Wallet/AddDebitCardPage.js | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index e75c3b2c517e..23532346a990 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -22,6 +22,8 @@ import ROUTES from '../../../ROUTES'; import usePrevious from '../../../hooks/usePrevious'; import NotFoundPage from '../../ErrorPage/NotFoundPage'; import Permissions from '../../../libs/Permissions'; +import FormProvider from "../../../components/Form/FormProvider"; +import InputWrapper from "../../../components/Form/InputWrapper"; const propTypes = { /* Onyx Props */ @@ -114,7 +116,7 @@ function DebitCardPage(props) { title={translate('addDebitCardPage.addADebitCard')} onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_WALLET)} /> -
- (nameOnCardRef.current = ref)} spellCheck={false} /> - - - - - - + - ( @@ -195,7 +204,7 @@ function DebitCardPage(props) { )} style={[styles.mt4]} /> - + ); } From a348d1ba55eb224a53538f5afc9cd9c7b215a97b Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 19 Oct 2023 15:26:34 +0200 Subject: [PATCH 040/128] Fix checkbox proptypes --- src/components/CheckboxWithLabel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js index 63c067c93234..777c46f861aa 100644 --- a/src/components/CheckboxWithLabel.js +++ b/src/components/CheckboxWithLabel.js @@ -54,7 +54,7 @@ const propTypes = { defaultValue: PropTypes.bool, /** React ref being forwarded to the Checkbox input */ - forwardedRef: PropTypes.func, + forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]), /** The ID used to uniquely identify the input in a Form */ /* eslint-disable-next-line react/no-unused-prop-types */ From 38d91848c62674d56b4137fdce9c1f482b4e46bd Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 19 Oct 2023 15:27:14 +0200 Subject: [PATCH 041/128] Fix address search prop type issue --- src/components/AddressSearch/index.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index 3e676b811c16..3fac925cdb0a 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -1,7 +1,7 @@ import _ from 'underscore'; -import React, {useEffect, useMemo, useRef, useState} from 'react'; +import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; import PropTypes from 'prop-types'; -import {Keyboard, LogBox, ScrollView, View, Text, ActivityIndicator} from 'react-native'; +import {ActivityIndicator, Keyboard, LogBox, ScrollView, Text, View} from 'react-native'; import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete'; import lodashGet from 'lodash/get'; import compose from '../../libs/compose'; @@ -137,6 +137,16 @@ const defaultProps = { resultTypes: 'address', }; +function listLoader() { + return memo(() => ( + + )); +} + + // Do not convert to class component! It's been tried before and presents more challenges than it's worth. // Relevant thread: https://expensify.slack.com/archives/C03TQ48KC/p1634088400387400 // Reference: https://github.com/FaridSafi/react-native-google-places-autocomplete/issues/609#issuecomment-886133839 @@ -374,14 +384,7 @@ function AddressSearch(props) { {props.translate('common.noResultsFound')} ) } - listLoaderComponent={ - - - - } + listLoaderComponent={listLoader} renderHeaderComponent={renderHeaderComponent} onPress={(data, details) => { saveLocationDetails(data, details); From 00e12fc524860cc05fa5c34929a3ccec21e5efb5 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 19 Oct 2023 15:27:36 +0200 Subject: [PATCH 042/128] Add checkbox default value --- src/pages/settings/Wallet/AddDebitCardPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index 23532346a990..ad284da16827 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -196,6 +196,7 @@ function DebitCardPage(props) { InputComponent={CheckboxWithLabel} accessibilityLabel={`${translate('common.iAcceptThe')} ${translate('common.expensifyTermsOfService')}`} inputID="acceptTerms" + defaultValue={false} LabelComponent={() => ( {`${translate('common.iAcceptThe')}`} From 6b401e0e1d6631889f93e1fc1a16f19a068ba5e0 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 19 Oct 2023 08:11:06 -0600 Subject: [PATCH 043/128] Fix lint --- src/libs/ReportUtils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index 7a376c59e6a3..3b72e6829c39 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3664,7 +3664,6 @@ function getAddWorkspaceRoomOrChatReportErrors(report) { */ function canUserPerformWriteAction(report) { const reportErrors = getAddWorkspaceRoomOrChatReportErrors(report); - return isArchivedRoom(report) || !_.isEmpty(reportErrors) || !isAllowedToComment(report) || isAnonymousUser; return !isArchivedRoom(report) && _.isEmpty(reportErrors) && isAllowedToComment(report) && !isAnonymousUser; } From b05c8bab57672e9a00aeb1b86b1efcdc9d1bf228 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 19 Oct 2023 16:25:41 +0200 Subject: [PATCH 044/128] Prettier --- src/pages/settings/Wallet/AddDebitCardPage.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index ad284da16827..b0196e8e620e 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -22,8 +22,8 @@ import ROUTES from '../../../ROUTES'; import usePrevious from '../../../hooks/usePrevious'; import NotFoundPage from '../../ErrorPage/NotFoundPage'; import Permissions from '../../../libs/Permissions'; -import FormProvider from "../../../components/Form/FormProvider"; -import InputWrapper from "../../../components/Form/InputWrapper"; +import FormProvider from '../../../components/Form/FormProvider'; +import InputWrapper from '../../../components/Form/InputWrapper'; const propTypes = { /* Onyx Props */ @@ -190,7 +190,10 @@ function DebitCardPage(props) { containerStyles={[styles.mt4]} /> - + Date: Thu, 19 Oct 2023 16:25:56 +0200 Subject: [PATCH 045/128] Spread props --- src/components/AddressSearch/index.js | 146 +++++++++++++++----------- 1 file changed, 86 insertions(+), 60 deletions(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index 3fac925cdb0a..db8d6b6bae42 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import React, {memo, useEffect, useMemo, useRef, useState} from 'react'; +import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'; import PropTypes from 'prop-types'; import {ActivityIndicator, Keyboard, LogBox, ScrollView, Text, View} from 'react-native'; import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete'; @@ -137,37 +137,49 @@ const defaultProps = { resultTypes: 'address', }; -function listLoader() { - return memo(() => ( - - )); -} - - // Do not convert to class component! It's been tried before and presents more challenges than it's worth. // Relevant thread: https://expensify.slack.com/archives/C03TQ48KC/p1634088400387400 // Reference: https://github.com/FaridSafi/react-native-google-places-autocomplete/issues/609#issuecomment-886133839 -function AddressSearch(props) { +function AddressSearch({ + canUseCurrentLocation, + containerStyles, + defaultValue, + errorText, + hint, + innerRef, + inputID, + isLimitedToUSA, + label, + maxInputLength, + network, + onBlur, + onInputChange, + onPress, + predefinedPlaces, + preferredLocale, + renamedInputKeys, + resultTypes, + shouldSaveDraft, + translate, + value, +}) { const [displayListViewBorder, setDisplayListViewBorder] = useState(false); const [isTyping, setIsTyping] = useState(false); const [isFocused, setIsFocused] = useState(false); - const [searchValue, setSearchValue] = useState(props.value || props.defaultValue || ''); + const [searchValue, setSearchValue] = useState(value || defaultValue || ''); const [locationErrorCode, setLocationErrorCode] = useState(null); const [isFetchingCurrentLocation, setIsFetchingCurrentLocation] = useState(false); const shouldTriggerGeolocationCallbacks = useRef(true); const containerRef = useRef(); const query = useMemo( () => ({ - language: props.preferredLocale, - types: props.resultTypes, - components: props.isLimitedToUSA ? 'country:us' : undefined, + language: preferredLocale, + types: resultTypes, + components: isLimitedToUSA ? 'country:us' : undefined, }), - [props.preferredLocale, props.resultTypes, props.isLimitedToUSA], + [preferredLocale, resultTypes, isLimitedToUSA], ); - const shouldShowCurrentLocationButton = props.canUseCurrentLocation && searchValue.trim().length === 0 && isFocused; + const shouldShowCurrentLocationButton = canUseCurrentLocation && searchValue.trim().length === 0 && isFocused; const saveLocationDetails = (autocompleteData, details) => { const addressComponents = details.address_components; @@ -176,7 +188,7 @@ function AddressSearch(props) { // to this component which don't match the usual properties coming from auto-complete. In that case, only a limited // amount of data massaging needs to happen for what the parent expects to get from this function. if (_.size(details)) { - props.onPress({ + onPress({ address: lodashGet(details, 'description', ''), lat: lodashGet(details, 'geometry.location.lat', 0), lng: lodashGet(details, 'geometry.location.lng', 0), @@ -262,7 +274,7 @@ function AddressSearch(props) { // Not all pages define the Address Line 2 field, so in that case we append any additional address details // (e.g. Apt #) to Address Line 1 - if (subpremise && typeof props.renamedInputKeys.street2 === 'undefined') { + if (subpremise && typeof renamedInputKeys.street2 === 'undefined') { values.street += `, ${subpremise}`; } @@ -271,19 +283,19 @@ function AddressSearch(props) { values.country = country; } - if (props.inputID) { - _.each(values, (value, key) => { - const inputKey = lodashGet(props.renamedInputKeys, key, key); + if (inputID) { + _.each(values, (inputValue, key) => { + const inputKey = lodashGet(renamedInputKeys, key, key); if (!inputKey) { return; } - props.onInputChange(value, inputKey); + onInputChange(inputValue, inputKey); }); } else { - props.onInputChange(values); + onInputChange(values); } - props.onPress(values); + onPress(values); }; /** Gets the user's current location and registers success/error callbacks */ @@ -313,7 +325,7 @@ function AddressSearch(props) { lng: successData.coords.longitude, address: CONST.YOUR_LOCATION_TEXT, }; - props.onPress(location); + onPress(location); }, (errorData) => { if (!shouldTriggerGeolocationCallbacks.current) { @@ -331,16 +343,16 @@ function AddressSearch(props) { }; const renderHeaderComponent = () => - props.predefinedPlaces.length > 0 && ( + predefinedPlaces.length > 0 && ( <> {/* This will show current location button in list if there are some recent destinations */} {shouldShowCurrentLocationButton && ( )} - {!props.value && {props.translate('common.recentDestinations')}} + {!value && {translate('common.recentDestinations')}} ); @@ -352,6 +364,26 @@ function AddressSearch(props) { }; }, []); + const listEmptyComponent = useCallback( + () => + network.isOffline || !isTyping ? null : ( + {translate('common.noResultsFound')} + ), + [isTyping, translate, network.isOffline], + ); + + const listLoader = useCallback( + () => ( + + + + ), + [], + ); + return ( /* * The GooglePlacesAutocomplete component uses a VirtualizedList internally, @@ -378,12 +410,8 @@ function AddressSearch(props) { fetchDetails suppressDefaultStyles enablePoweredByContainer={false} - predefinedPlaces={props.predefinedPlaces} - listEmptyComponent={ - props.network.isOffline || !isTyping ? null : ( - {props.translate('common.noResultsFound')} - ) - } + predefinedPlaces={predefinedPlaces} + listEmptyComponent={listEmptyComponent} listLoaderComponent={listLoader} renderHeaderComponent={renderHeaderComponent} onPress={(data, details) => { @@ -400,34 +428,31 @@ function AddressSearch(props) { query={query} requestUrl={{ useOnPlatform: 'all', - url: props.network.isOffline ? null : ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces&proxyUrl='}), + url: network.isOffline ? null : ApiUtils.getCommandURL({command: 'Proxy_GooglePlaces&proxyUrl='}), }} textInputProps={{ InputComp: TextInput, ref: (node) => { - if (!props.innerRef) { + if (!innerRef) { return; } - if (_.isFunction(props.innerRef)) { - props.innerRef(node); + if (_.isFunction(innerRef)) { + innerRef(node); return; } // eslint-disable-next-line no-param-reassign - props.innerRef.current = node; + innerRef.current = node; }, - label: props.label, - containerStyles: props.containerStyles, - errorText: props.errorText, - hint: - displayListViewBorder || (props.predefinedPlaces.length === 0 && shouldShowCurrentLocationButton) || (props.canUseCurrentLocation && isTyping) - ? undefined - : props.hint, - value: props.value, - defaultValue: props.defaultValue, - inputID: props.inputID, - shouldSaveDraft: props.shouldSaveDraft, + label, + containerStyles, + errorText, + hint: displayListViewBorder || (predefinedPlaces.length === 0 && shouldShowCurrentLocationButton) || (canUseCurrentLocation && isTyping) ? undefined : hint, + value, + defaultValue, + inputID, + shouldSaveDraft, onFocus: () => { setIsFocused(true); }, @@ -437,24 +462,24 @@ function AddressSearch(props) { setIsFocused(false); setIsTyping(false); } - props.onBlur(); + onBlur(); }, autoComplete: 'off', onInputChange: (text) => { setSearchValue(text); setIsTyping(true); - if (props.inputID) { - props.onInputChange(text); + if (inputID) { + onInputChange(text); } else { - props.onInputChange({street: text}); + onInputChange({street: text}); } // If the text is empty and we have no predefined places, we set displayListViewBorder to false to prevent UI flickering - if (_.isEmpty(text) && _.isEmpty(props.predefinedPlaces)) { + if (_.isEmpty(text) && _.isEmpty(predefinedPlaces)) { setDisplayListViewBorder(false); } }, - maxLength: props.maxInputLength, + maxLength: maxInputLength, spellCheck: false, }} styles={{ @@ -475,17 +500,18 @@ function AddressSearch(props) { }} inbetweenCompo={ // We want to show the current location button even if there are no recent destinations - props.predefinedPlaces.length === 0 && shouldShowCurrentLocationButton ? ( + predefinedPlaces.length === 0 && shouldShowCurrentLocationButton ? ( ) : ( <> ) } + placeholder="" /> setLocationErrorCode(null)} From 64dbcd48507efa6329be72a437f85fabed6e31a6 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 19 Oct 2023 17:45:01 +0200 Subject: [PATCH 046/128] Lint fix --- src/components/AddressSearch/index.js | 2 +- src/pages/settings/Wallet/AddDebitCardPage.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index db8d6b6bae42..7c754a33e370 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import React, {memo, useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import PropTypes from 'prop-types'; import {ActivityIndicator, Keyboard, LogBox, ScrollView, Text, View} from 'react-native'; import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete'; diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index b0196e8e620e..b9ea0ac6df3a 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -16,7 +16,6 @@ import TextInput from '../../../components/TextInput'; import CONST from '../../../CONST'; import ONYXKEYS from '../../../ONYXKEYS'; import AddressSearch from '../../../components/AddressSearch'; -import Form from '../../../components/Form'; import Navigation from '../../../libs/Navigation/Navigation'; import ROUTES from '../../../ROUTES'; import usePrevious from '../../../hooks/usePrevious'; From cf90f7bd132d9562b80a09a6e027be38a8fd6d9a Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Thu, 19 Oct 2023 09:47:00 -0600 Subject: [PATCH 047/128] Negate logic for the referenced variable --- src/libs/SidebarUtils.js | 2 +- src/pages/home/report/ReportActionsList.js | 2 +- src/pages/home/report/ReportFooter.js | 2 +- src/pages/iou/steps/NewRequestAmountPage.js | 2 +- src/pages/tasks/TaskShareDestinationSelectorModal.js | 2 +- tests/unit/OptionsListUtilsTest.js | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.js index 2c679ef3cda7..6eb07c6b19e0 100644 --- a/src/libs/SidebarUtils.js +++ b/src/libs/SidebarUtils.js @@ -305,7 +305,7 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale, result.parentReportID = report.parentReportID || null; result.isWaitingOnBankAccount = report.isWaitingOnBankAccount; result.notificationPreference = report.notificationPreference || null; - result.isAllowedToComment = !ReportUtils.canUserPerformWriteAction(report); + result.isAllowedToComment = ReportUtils.canUserPerformWriteAction(report); const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat; const subtitle = ReportUtils.getChatRoomSubtitle(report); diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index e986c7b53528..32499ebc4090 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -334,7 +334,7 @@ function ReportActionsList({ // Native mobile does not render updates flatlist the changes even though component did update called. // To notify there something changes we can use extraData prop to flatlist const extraData = [isSmallScreenWidth ? currentUnreadMarker : undefined, ReportUtils.isArchivedRoom(report)]; - const hideComposer = ReportUtils.canUserPerformWriteAction(report); + const hideComposer = !ReportUtils.canUserPerformWriteAction(report); const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(personalDetailsList, report, currentUserPersonalDetails.accountID) && !isComposerFullSize; const renderFooter = useCallback(() => { diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js index c96824770f07..754fae8d670a 100644 --- a/src/pages/home/report/ReportFooter.js +++ b/src/pages/home/report/ReportFooter.js @@ -70,7 +70,7 @@ function ReportFooter(props) { const isAnonymousUser = Session.isAnonymousUser(); const isSmallSizeLayout = props.windowWidth - (props.isSmallScreenWidth ? 0 : variables.sideBarWidth) < variables.anonymousReportFooterBreakpoint; - const hideComposer = ReportUtils.canUserPerformWriteAction(props.report); + const hideComposer = !ReportUtils.canUserPerformWriteAction(props.report); return ( <> diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js index dda52352e015..c624973a0189 100644 --- a/src/pages/iou/steps/NewRequestAmountPage.js +++ b/src/pages/iou/steps/NewRequestAmountPage.js @@ -85,7 +85,7 @@ function NewRequestAmountPage({route, iou, report, selectedTab}) { // Check and dismiss modal useEffect(() => { - if (!ReportUtils.canUserPerformWriteAction(report)) { + if (ReportUtils.canUserPerformWriteAction(report)) { return; } Navigation.dismissModal(reportID); diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.js b/src/pages/tasks/TaskShareDestinationSelectorModal.js index f1cd009d197d..32e02e7ba42e 100644 --- a/src/pages/tasks/TaskShareDestinationSelectorModal.js +++ b/src/pages/tasks/TaskShareDestinationSelectorModal.js @@ -52,7 +52,7 @@ function TaskShareDestinationSelectorModal(props) { const reports = {}; _.keys(props.reports).forEach((reportKey) => { if ( - ReportUtils.canUserPerformWriteAction(props.reports[reportKey]) || + !ReportUtils.canUserPerformWriteAction(props.reports[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(props.reports[reportKey]) || ReportUtils.isCanceledTaskReport(props.reports[reportKey]) ) { diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js index 0032f6a1ad42..50edfa7f0522 100644 --- a/tests/unit/OptionsListUtilsTest.js +++ b/tests/unit/OptionsListUtilsTest.js @@ -590,7 +590,7 @@ describe('OptionsListUtils', () => { // Filter current REPORTS as we do in the component, before getting share destination options const filteredReports = {}; _.keys(REPORTS).forEach((reportKey) => { - if (ReportUtils.canUserPerformWriteAction(REPORTS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS[reportKey])) { + if (!ReportUtils.canUserPerformWriteAction(REPORTS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS[reportKey])) { return; } filteredReports[reportKey] = REPORTS[reportKey]; @@ -617,7 +617,7 @@ describe('OptionsListUtils', () => { // Filter current REPORTS_WITH_WORKSPACE_ROOMS as we do in the component, before getting share destination options const filteredReportsWithWorkspaceRooms = {}; _.keys(REPORTS_WITH_WORKSPACE_ROOMS).forEach((reportKey) => { - if (ReportUtils.canUserPerformWriteAction(REPORTS_WITH_WORKSPACE_ROOMS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS_WITH_WORKSPACE_ROOMS[reportKey])) { + if (!ReportUtils.canUserPerformWriteAction(REPORTS_WITH_WORKSPACE_ROOMS[reportKey]) || ReportUtils.isExpensifyOnlyParticipantInReport(REPORTS_WITH_WORKSPACE_ROOMS[reportKey])) { return; } filteredReportsWithWorkspaceRooms[reportKey] = REPORTS_WITH_WORKSPACE_ROOMS[reportKey]; From 196689db016c212d18b43e13b8316a17cdbc6193 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Fri, 20 Oct 2023 16:35:47 +0200 Subject: [PATCH 048/128] Fix propType --- src/components/CheckboxWithLabel.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js index 777c46f861aa..70fa972a5d2f 100644 --- a/src/components/CheckboxWithLabel.js +++ b/src/components/CheckboxWithLabel.js @@ -8,6 +8,7 @@ import Text from './Text'; import FormHelpMessage from './FormHelpMessage'; import variables from '../styles/variables'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; +import refPropTypes from "./refPropTypes"; /** * Returns an error if the required props are not provided @@ -54,7 +55,7 @@ const propTypes = { defaultValue: PropTypes.bool, /** React ref being forwarded to the Checkbox input */ - forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]), + forwardedRef: refPropTypes, /** The ID used to uniquely identify the input in a Form */ /* eslint-disable-next-line react/no-unused-prop-types */ From 0daa9f1dcc04a37f8516141ad25584f2fc2e8b82 Mon Sep 17 00:00:00 2001 From: jeet-dhandha Date: Sat, 21 Oct 2023 09:46:45 +0530 Subject: [PATCH 049/128] fix: console error old-dot to new-dot new workspace transition --- .../Navigators/CentralPaneNavigator.js | 2 +- src/libs/ReportUtils.js | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js index 64eadcbe06c3..9c2bd6820e85 100644 --- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js +++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js @@ -18,7 +18,7 @@ function CentralPaneNavigator() { Date: Mon, 23 Oct 2023 10:15:02 +0700 Subject: [PATCH 050/128] fix update the latest change in staging --- src/libs/actions/App.js | 31 +++---------------- .../FloatingActionButtonAndPopover.js | 2 +- 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 42efa0353fd5..d4837a0b17a4 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -333,14 +333,7 @@ function endSignOnTransition() { * @param {Boolean} [isThereModalToDismiss] Optional, if there is a modal to dismiss */ -function createWorkspaceAndNavigateToIt( - policyOwnerEmail = '', - makeMeAdmin = false, - policyName = '', - transitionFromOldDot = false, - shouldNavigateToAdminChat = true, - isThereModalToDismiss = true, -) { +function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', transitionFromOldDot = false, shouldNavigateToAdminChat = true) { const policyID = Policy.generatePolicyID(); const adminsChatReportID = Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); Navigation.isNavigationReady() @@ -351,26 +344,10 @@ function createWorkspaceAndNavigateToIt( } if (shouldNavigateToAdminChat) { - if (isThereModalToDismiss) { - Navigation.dismissModal(adminsChatReportID); - setTimeout(() => { - Navigation.navigate(ROUTES.SETTINGS); - setTimeout(() => { - Navigation.navigate(ROUTES.SETTINGS_WORKSPACES); - setTimeout(() => { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); - }, 50); - }, 50); - }, 50); - } else { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID)); - setTimeout(() => { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); - }, 50); - } - } else { - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); + Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID)); } + + Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); }) .then(endSignOnTransition); } diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 5932049cd32c..02f1856c7bf5 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -228,7 +228,7 @@ function FloatingActionButtonAndPopover(props) { iconHeight: 40, text: props.translate('workspace.new.newWorkspace'), description: props.translate('workspace.new.getTheExpensifyCardAndMore'), - onSelected: () => interceptAnonymousUser(() => App.createWorkspaceAndNavigateToIt('', false, '', false, !props.isSmallScreenWidth, false)), + onSelected: () => interceptAnonymousUser(() => App.createWorkspaceAndNavigateToIt('', false, '', false, !props.isSmallScreenWidth)), }, ] : []), From 54a01bb3a1153a629d70c78b2a4f4ac5e7e91add Mon Sep 17 00:00:00 2001 From: DylanDylann Date: Mon, 23 Oct 2023 10:52:30 +0700 Subject: [PATCH 051/128] fix on press create new workspace --- src/libs/actions/App.js | 2 -- .../sidebar/SidebarScreen/FloatingActionButtonAndPopover.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index d4837a0b17a4..75520d483f98 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -330,8 +330,6 @@ function endSignOnTransition() { * @param {String} [policyName] Optional, custom policy name we will use for created workspace * @param {Boolean} [transitionFromOldDot] Optional, if the user is transitioning from old dot * @param {Boolean} [shouldNavigateToAdminChat] Optional, navigate to the #admin room after creation - * @param {Boolean} [isThereModalToDismiss] Optional, if there is a modal to dismiss - */ function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', transitionFromOldDot = false, shouldNavigateToAdminChat = true) { const policyID = Policy.generatePolicyID(); diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 02f1856c7bf5..1bbb64d99c2b 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -228,7 +228,7 @@ function FloatingActionButtonAndPopover(props) { iconHeight: 40, text: props.translate('workspace.new.newWorkspace'), description: props.translate('workspace.new.getTheExpensifyCardAndMore'), - onSelected: () => interceptAnonymousUser(() => App.createWorkspaceAndNavigateToIt('', false, '', false, !props.isSmallScreenWidth)), + onSelected: () => interceptAnonymousUser(() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()), }, ] : []), From d0ea5b9175ddce96d464c28d6f13fd06d149f526 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Fri, 20 Oct 2023 10:59:05 +0200 Subject: [PATCH 052/128] Add FormProvider to NewTaskDescriptionPage --- src/pages/tasks/NewTaskDescriptionPage.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/tasks/NewTaskDescriptionPage.js b/src/pages/tasks/NewTaskDescriptionPage.js index 44fd4346538d..378adf6a9a41 100644 --- a/src/pages/tasks/NewTaskDescriptionPage.js +++ b/src/pages/tasks/NewTaskDescriptionPage.js @@ -10,7 +10,6 @@ import Navigation from '../../libs/Navigation/Navigation'; import ScreenWrapper from '../../components/ScreenWrapper'; import styles from '../../styles/styles'; import ONYXKEYS from '../../ONYXKEYS'; -import Form from '../../components/Form'; import TextInput from '../../components/TextInput'; import Permissions from '../../libs/Permissions'; import ROUTES from '../../ROUTES'; @@ -18,6 +17,8 @@ import * as Task from '../../libs/actions/Task'; import updateMultilineInputRange from '../../libs/UpdateMultilineInputRange'; import CONST from '../../CONST'; import * as Browser from '../../libs/Browser'; +import FormProvider from '../../components/Form/FormProvider'; +import InputWrapper from '../../components/Form/InputWrapper'; const propTypes = { /** Beta features list */ @@ -82,7 +83,7 @@ function NewTaskDescriptionPage(props) { onCloseButtonPress={() => Task.dismissModalAndClearOutTaskInfo()} onBackButtonPress={() => Navigation.goBack(ROUTES.NEW_TASK)} /> -
- -
+ ); From d402f9c15e909c7aa834af87145015ea5e647dda Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 23 Oct 2023 13:10:18 +0200 Subject: [PATCH 053/128] Add FormProvider in NewTaskTitlePage --- src/pages/tasks/NewTaskTitlePage.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/tasks/NewTaskTitlePage.js b/src/pages/tasks/NewTaskTitlePage.js index 62eb1da4872a..2a8d776eaefd 100644 --- a/src/pages/tasks/NewTaskTitlePage.js +++ b/src/pages/tasks/NewTaskTitlePage.js @@ -10,12 +10,13 @@ import ScreenWrapper from '../../components/ScreenWrapper'; import styles from '../../styles/styles'; import ONYXKEYS from '../../ONYXKEYS'; import * as ErrorUtils from '../../libs/ErrorUtils'; -import Form from '../../components/Form'; import TextInput from '../../components/TextInput'; import Permissions from '../../libs/Permissions'; import ROUTES from '../../ROUTES'; import * as Task from '../../libs/actions/Task'; import CONST from '../../CONST'; +import FormProvider from '../../components/Form/FormProvider'; +import InputWrapper from '../../components/Form/InputWrapper'; const propTypes = { /** Beta features list */ @@ -85,7 +86,7 @@ function NewTaskTitlePage(props) { shouldShowBackButton onBackButtonPress={() => Navigation.goBack(ROUTES.NEW_TASK)} /> -
- (inputRef.current = el)} @@ -103,7 +105,7 @@ function NewTaskTitlePage(props) { accessibilityLabel={props.translate('task.title')} /> -
+ ); } From dd85519875f12ef3d37a990e862501205e9fa153 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 23 Oct 2023 15:07:23 +0200 Subject: [PATCH 054/128] Add FormProvider in MoneyRequestDescriptionPage --- src/pages/iou/MoneyRequestDescriptionPage.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/iou/MoneyRequestDescriptionPage.js b/src/pages/iou/MoneyRequestDescriptionPage.js index cfdbb60b4f0d..4c2ae3bdf4ae 100644 --- a/src/pages/iou/MoneyRequestDescriptionPage.js +++ b/src/pages/iou/MoneyRequestDescriptionPage.js @@ -9,7 +9,6 @@ import {iouPropTypes, iouDefaultProps} from './propTypes'; import TextInput from '../../components/TextInput'; import ScreenWrapper from '../../components/ScreenWrapper'; import HeaderWithBackButton from '../../components/HeaderWithBackButton'; -import Form from '../../components/Form'; import ONYXKEYS from '../../ONYXKEYS'; import styles from '../../styles/styles'; import Navigation from '../../libs/Navigation/Navigation'; @@ -20,6 +19,8 @@ import CONST from '../../CONST'; import useLocalize from '../../hooks/useLocalize'; import updateMultilineInputRange from '../../libs/UpdateMultilineInputRange'; import * as Browser from '../../libs/Browser'; +import FormProvider from '../../components/Form/FormProvider'; +import InputWrapper from '../../components/Form/InputWrapper'; const propTypes = { /** Onyx Props */ @@ -115,7 +116,7 @@ function MoneyRequestDescriptionPage({iou, route, selectedTab}) { title={translate('common.description')} onBackButtonPress={() => navigateBack()} /> -
updateComment(value)} @@ -123,7 +124,8 @@ function MoneyRequestDescriptionPage({iou, route, selectedTab}) { enabledWhenOffline > - -
+ ); From b418a4cb7561b597c3423b5602cbeb491b8d63fc Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Mon, 23 Oct 2023 15:35:53 +0200 Subject: [PATCH 055/128] Code review changes --- src/components/AddressSearch/index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index 7c754a33e370..a4f712435af3 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -137,9 +137,6 @@ const defaultProps = { resultTypes: 'address', }; -// Do not convert to class component! It's been tried before and presents more challenges than it's worth. -// Relevant thread: https://expensify.slack.com/archives/C03TQ48KC/p1634088400387400 -// Reference: https://github.com/FaridSafi/react-native-google-places-autocomplete/issues/609#issuecomment-886133839 function AddressSearch({ canUseCurrentLocation, containerStyles, @@ -372,7 +369,7 @@ function AddressSearch({ [isTyping, translate, network.isOffline], ); - const listLoader = useCallback( + const listLoader = useMemo( () => ( Date: Mon, 23 Oct 2023 22:03:31 +0700 Subject: [PATCH 056/128] fix remove createWorkspaceAndNavigateToIt --- .../Navigation/AppNavigator/AuthScreens.js | 2 +- src/libs/actions/App.js | 39 +++---------------- src/libs/actions/Policy.js | 4 +- src/pages/workspace/WorkspaceInitialPage.js | 2 +- src/pages/workspace/WorkspaceNewRoomPage.js | 2 +- 5 files changed, 11 insertions(+), 38 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index dd7175dbc6f6..8b07034400a3 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -184,7 +184,7 @@ class AuthScreens extends React.Component { App.reconnectApp(this.props.lastUpdateIDAppliedToClient); } - App.setUpPoliciesAndNavigate(this.props.session, !this.props.isSmallScreenWidth); + App.setUpPoliciesAndNavigate(this.props.session); App.redirectThirdPartyDesktopSignIn(); // Check if we should be running any demos immediately after signing in. diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js index 75520d483f98..678b5f9f4594 100644 --- a/src/libs/actions/App.js +++ b/src/libs/actions/App.js @@ -322,44 +322,17 @@ function endSignOnTransition() { return resolveSignOnTransitionToFinishPromise(); } -/** - * Create a new workspace and navigate to it - * - * @param {String} [policyOwnerEmail] Optional, the email of the account to make the owner of the policy - * @param {Boolean} [makeMeAdmin] Optional, leave the calling account as an admin on the policy - * @param {String} [policyName] Optional, custom policy name we will use for created workspace - * @param {Boolean} [transitionFromOldDot] Optional, if the user is transitioning from old dot - * @param {Boolean} [shouldNavigateToAdminChat] Optional, navigate to the #admin room after creation - */ -function createWorkspaceAndNavigateToIt(policyOwnerEmail = '', makeMeAdmin = false, policyName = '', transitionFromOldDot = false, shouldNavigateToAdminChat = true) { - const policyID = Policy.generatePolicyID(); - const adminsChatReportID = Policy.createWorkspace(policyOwnerEmail, makeMeAdmin, policyName, policyID); - Navigation.isNavigationReady() - .then(() => { - if (transitionFromOldDot) { - // We must call goBack() to remove the /transition route from history - Navigation.goBack(ROUTES.HOME); - } - - if (shouldNavigateToAdminChat) { - Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(adminsChatReportID)); - } - - Navigation.navigate(ROUTES.WORKSPACE_INITIAL.getRoute(policyID)); - }) - .then(endSignOnTransition); -} - /** * Create a new draft workspace and navigate to it * * @param {String} [policyOwnerEmail] Optional, the email of the account to make the owner of the policy * @param {String} [policyName] Optional, custom policy name we will use for created workspace * @param {Boolean} [transitionFromOldDot] Optional, if the user is transitioning from old dot + * @param {Boolean} [makeMeAdmin] Optional, leave the calling account as an admin on the policy */ -function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', policyName = '', transitionFromOldDot = false) { +function createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail = '', policyName = '', transitionFromOldDot = false, makeMeAdmin = false) { const policyID = Policy.generatePolicyID(); - Policy.createDraftInitialWorkspace(policyOwnerEmail, policyName, policyID); + Policy.createDraftInitialWorkspace(policyOwnerEmail, policyName, policyID, makeMeAdmin); Navigation.isNavigationReady() .then(() => { @@ -403,9 +376,8 @@ function savePolicyDraftByNewWorkspace(policyID, policyName, policyOwnerEmail = * pass it in as a parameter. withOnyx guarantees that the value has been read * from Onyx because it will not render the AuthScreens until that point. * @param {Object} session - * @param {Boolean} shouldNavigateToAdminChat Should we navigate to admin chat after creating workspace */ -function setUpPoliciesAndNavigate(session, shouldNavigateToAdminChat) { +function setUpPoliciesAndNavigate(session) { const currentUrl = getCurrentUrl(); if (!session || !currentUrl || !currentUrl.includes('exitTo')) { return; @@ -426,7 +398,7 @@ function setUpPoliciesAndNavigate(session, shouldNavigateToAdminChat) { const shouldCreateFreePolicy = !isLoggingInAsNewUser && isTransitioning && exitTo === ROUTES.WORKSPACE_NEW; if (shouldCreateFreePolicy) { - createWorkspaceAndNavigateToIt(policyOwnerEmail, makeMeAdmin, policyName, true, shouldNavigateToAdminChat); + createWorkspaceWithPolicyDraftAndNavigateToIt(policyOwnerEmail, policyName, true, makeMeAdmin); return; } if (!isLoggingInAsNewUser && exitTo) { @@ -555,7 +527,6 @@ export { handleRestrictedEvent, beginDeepLinkRedirect, beginDeepLinkRedirectAfterTransition, - createWorkspaceAndNavigateToIt, getMissingOnyxUpdates, finalReconnectAppAfterActivatingReliableUpdates, savePolicyDraftByNewWorkspace, diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 89324dd35485..a239ca691de3 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -922,8 +922,9 @@ function buildOptimisticCustomUnits() { * @param {String} [policyOwnerEmail] Optional, the email of the account to make the owner of the policy * @param {String} [policyName] Optional, custom policy name we will use for created workspace * @param {String} [policyID] Optional, custom policy id we will use for created workspace + * @param {Boolean} [makeMeAdmin] Optional, leave the calling account as an admin on the policy */ -function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', policyID = generatePolicyID()) { +function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', policyID = generatePolicyID(), makeMeAdmin = false) { const workspaceName = policyName || generateDefaultWorkspaceName(policyOwnerEmail); const {customUnits} = buildOptimisticCustomUnits(); @@ -941,6 +942,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD), pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD, customUnits, + makeMeAdmin, }, }, { diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js index d275b7f0dd10..edaa1b29bffd 100644 --- a/src/pages/workspace/WorkspaceInitialPage.js +++ b/src/pages/workspace/WorkspaceInitialPage.js @@ -88,7 +88,7 @@ function WorkspaceInitialPage(props) { return; } - App.savePolicyDraftByNewWorkspace(props.policyDraft.id, props.policyDraft.name, '', false); + App.savePolicyDraftByNewWorkspace(props.policyDraft.id, props.policyDraft.name, '', props.policyDraft.makeMeAdmin); // We only care when the component renders the first time // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js index da0bf845cc81..8a62a3b876ea 100644 --- a/src/pages/workspace/WorkspaceNewRoomPage.js +++ b/src/pages/workspace/WorkspaceNewRoomPage.js @@ -165,7 +165,7 @@ function WorkspaceNewRoomPage(props) { shouldShow={!Permissions.canUsePolicyRooms(props.betas) || !workspaceOptions.length} shouldShowBackButton={false} linkKey="workspace.emptyWorkspace.title" - onLinkPress={() => App.createWorkspaceAndNavigateToIt('', false, '', false, false)} + onLinkPress={() => App.createWorkspaceWithPolicyDraftAndNavigateToIt()} > Date: Tue, 24 Oct 2023 15:14:57 +0530 Subject: [PATCH 057/128] enable maxHeight to avoid keyboard overlapping the save button --- src/pages/ReportWelcomeMessagePage.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/pages/ReportWelcomeMessagePage.js b/src/pages/ReportWelcomeMessagePage.js index 48dd07090ef4..0b572af69d2c 100644 --- a/src/pages/ReportWelcomeMessagePage.js +++ b/src/pages/ReportWelcomeMessagePage.js @@ -75,7 +75,11 @@ function ReportWelcomeMessagePage(props) { ); return ( - + Date: Tue, 24 Oct 2023 12:11:32 +0200 Subject: [PATCH 058/128] Fix not displaying all errors --- src/components/Form/FormProvider.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js index ada40c24ed89..5047903040f4 100644 --- a/src/components/Form/FormProvider.js +++ b/src/components/Form/FormProvider.js @@ -103,6 +103,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC const inputRefs = useRef(null); const touchedInputs = useRef({}); const [inputValues, setInputValues] = useState({}); + const submitPressed = useRef(false); const [errors, setErrors] = useState({}); const hasServerError = useMemo(() => Boolean(formState) && !_.isEmpty(formState.errors), [formState]); @@ -159,7 +160,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC throw new Error('Validate callback must return an empty object or an object with shape {inputID: error}'); } - const touchedInputErrors = _.pick(validateErrors, (inputValue, inputID) => Boolean(touchedInputs.current[inputID])); + const touchedInputErrors = _.pick(validateErrors, (inputValue, inputID) => Boolean(touchedInputs.current[inputID]) || submitPressed.current); if (!_.isEqual(errors, touchedInputErrors)) { setErrors(touchedInputErrors); @@ -181,6 +182,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC ); const submit = useCallback(() => { + submitPressed.current = true; // Return early if the form is already submitting to avoid duplicate submission if (formState.isLoading) { return; From 677c2a51fa139cc905459aa19ea1fe7c8d9f54e2 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Tue, 24 Oct 2023 12:15:15 +0200 Subject: [PATCH 059/128] Fix prettier --- src/components/CheckboxWithLabel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js index 70fa972a5d2f..8ce08caad54b 100644 --- a/src/components/CheckboxWithLabel.js +++ b/src/components/CheckboxWithLabel.js @@ -8,7 +8,7 @@ import Text from './Text'; import FormHelpMessage from './FormHelpMessage'; import variables from '../styles/variables'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; -import refPropTypes from "./refPropTypes"; +import refPropTypes from './refPropTypes'; /** * Returns an error if the required props are not provided From c2f54d3866962daed3d19fcb4e892f233ecfc1a4 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Tue, 24 Oct 2023 16:18:03 +0200 Subject: [PATCH 060/128] Remove unused ref --- src/components/Form/FormProvider.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js index ecd9f2322cc5..add58dbef18c 100644 --- a/src/components/Form/FormProvider.js +++ b/src/components/Form/FormProvider.js @@ -103,7 +103,6 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC const inputRefs = useRef({}); const touchedInputs = useRef({}); const [inputValues, setInputValues] = useState({}); - const submitPressed = useRef(false); const [errors, setErrors] = useState({}); const hasServerError = useMemo(() => Boolean(formState) && !_.isEmpty(formState.errors), [formState]); @@ -160,7 +159,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC throw new Error('Validate callback must return an empty object or an object with shape {inputID: error}'); } - const touchedInputErrors = _.pick(validateErrors, (inputValue, inputID) => Boolean(touchedInputs.current[inputID]) || submitPressed.current); + const touchedInputErrors = _.pick(validateErrors, (inputValue, inputID) => Boolean(touchedInputs.current[inputID])); if (!_.isEqual(errors, touchedInputErrors)) { setErrors(touchedInputErrors); @@ -182,7 +181,6 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC ); const submit = useCallback(() => { - submitPressed.current = true; // Return early if the form is already submitting to avoid duplicate submission if (formState.isLoading) { return; From 51fa6ed5dfc99e76f3132f9fe2833e4e05d81f88 Mon Sep 17 00:00:00 2001 From: Tim Golen Date: Tue, 24 Oct 2023 08:34:33 -0600 Subject: [PATCH 061/128] Rename a missed spot --- src/libs/ReportUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js index d49af6c84074..93f456b22ed5 100644 --- a/src/libs/ReportUtils.js +++ b/src/libs/ReportUtils.js @@ -3730,7 +3730,7 @@ function getPolicyExpenseChatReportIDByOwner(policyOwner) { */ function canCreateRequest(report, betas, iouType) { const participantAccountIDs = lodashGet(report, 'participantAccountIDs', []); - if (shouldDisableWriteActions(report)) { + if (!canUserPerformWriteAction(report)) { return false; } return getMoneyRequestOptions(report, participantAccountIDs, betas).includes(iouType); From 2cc169d984e5644d7cdb1698fd89b210cbc4fc83 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Tue, 24 Oct 2023 11:11:12 -0400 Subject: [PATCH 062/128] Update README.md Co-authored-by: Brandon Stites <42391420+stitesExpensify@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48c4cb03baf0..46eb240e310b 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ These instructions should get you set up ready to work on New Expensify ๐Ÿ™Œ 1. Install `nvm` then `node` & `npm`: `brew install nvm && nvm install` 2. Install `watchman`: `brew install watchman` 3. Install dependencies: `npm install` -4. Install `mkcert`: `brew install mkcert` followed by `npm run setup-https`. If you're using another OS, follow the instructions [here](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation). +4. Install `mkcert`: `brew install mkcert` followed by `npm run setup-https`. If you are not using macOS, follow the instructions [here](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation). 5. Create a host entry in your local hosts file, `/etc/hosts` for new.expensify.com.dev pointing to localhost: ``` 127.0.0.1 new.expensify.com.dev From 09e0d7400c47e79d39210a50433ede79684b1461 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Tue, 24 Oct 2023 18:29:11 +0200 Subject: [PATCH 063/128] Add FormProvider in EditRequestDescriptionPage --- src/pages/EditRequestDescriptionPage.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/pages/EditRequestDescriptionPage.js b/src/pages/EditRequestDescriptionPage.js index 0c0fcad7f60b..2a8bb8785124 100644 --- a/src/pages/EditRequestDescriptionPage.js +++ b/src/pages/EditRequestDescriptionPage.js @@ -5,13 +5,14 @@ import {useFocusEffect} from '@react-navigation/native'; import TextInput from '../components/TextInput'; import ScreenWrapper from '../components/ScreenWrapper'; import HeaderWithBackButton from '../components/HeaderWithBackButton'; -import Form from '../components/Form'; import ONYXKEYS from '../ONYXKEYS'; import styles from '../styles/styles'; import CONST from '../CONST'; import useLocalize from '../hooks/useLocalize'; import * as Browser from '../libs/Browser'; import updateMultilineInputRange from '../libs/UpdateMultilineInputRange'; +import FormProvider from '../components/Form/FormProvider'; +import InputWrapper from '../components/Form/InputWrapper'; const propTypes = { /** Transaction default description value */ @@ -49,7 +50,7 @@ function EditRequestDescriptionPage({defaultDescription, onSubmit}) { testID={EditRequestDescriptionPage.displayName} > -
- -
+
); } From b41c35a2c1c9956ae4e302fc0348a07b6edcd301 Mon Sep 17 00:00:00 2001 From: Kailash Devrari Date: Wed, 25 Oct 2023 01:59:03 +0530 Subject: [PATCH 064/128] fixed auto submit form when enter key pressed in selection modals --- .../NewDatePicker/CalendarPicker/YearPickerModal.js | 1 + src/components/SelectionList/BaseSelectionList.js | 2 ++ src/components/SelectionList/selectionListPropTypes.js | 3 +++ src/components/StatePicker/StateSelectorModal.js | 1 + src/components/ValuePicker/ValueSelectorModal.js | 1 + src/hooks/useKeyboardShortcut.js | 4 +++- src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js | 4 +++- src/libs/KeyboardShortcut/index.js | 4 +++- 8 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js b/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js index 9825109fbb63..1ceddfdc4778 100644 --- a/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js +++ b/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js @@ -82,6 +82,7 @@ function YearPickerModal(props) { onSelectRow={(option) => props.onYearChange(option.value)} initiallyFocusedOptionKey={props.currentYear.toString()} showScrollIndicator + shouldStopPropagation />
diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js index fdb1f92ca73b..db590d5e5439 100644 --- a/src/components/SelectionList/BaseSelectionList.js +++ b/src/components/SelectionList/BaseSelectionList.js @@ -57,6 +57,7 @@ function BaseSelectionList({ inputRef = null, disableKeyboardShortcuts = false, children, + shouldStopPropagation = false, }) { const {translate} = useLocalize(); const firstLayoutRef = useRef(true); @@ -339,6 +340,7 @@ function BaseSelectionList({ useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ENTER, selectFocusedOption, { captureOnInputs: true, shouldBubble: () => !flattenedSections.allOptions[focusedIndex], + shouldStopPropagation, isActive: !disableKeyboardShortcuts && !disableEnterShortcut && isFocused, }); diff --git a/src/components/SelectionList/selectionListPropTypes.js b/src/components/SelectionList/selectionListPropTypes.js index e75335e39b23..a0fb36bee917 100644 --- a/src/components/SelectionList/selectionListPropTypes.js +++ b/src/components/SelectionList/selectionListPropTypes.js @@ -168,6 +168,9 @@ const propTypes = { /** Whether to show the default confirm button */ showConfirmButton: PropTypes.bool, + /** Whether to stop automatic form submission on pressing enter key or not */ + shouldStopPropagation : PropTypes.bool, + /** Whether to prevent default focusing of options and focus the textinput when selecting an option */ shouldPreventDefaultFocusOnSelectRow: PropTypes.bool, diff --git a/src/components/StatePicker/StateSelectorModal.js b/src/components/StatePicker/StateSelectorModal.js index 378dcc4ebc8b..21ffea5bbdf8 100644 --- a/src/components/StatePicker/StateSelectorModal.js +++ b/src/components/StatePicker/StateSelectorModal.js @@ -99,6 +99,7 @@ function StateSelectorModal({currentState, isVisible, onClose, onStateSelected, onSelectRow={onStateSelected} onChangeText={setSearchValue} initiallyFocusedOptionKey={currentState} + shouldStopPropagation />
diff --git a/src/components/ValuePicker/ValueSelectorModal.js b/src/components/ValuePicker/ValueSelectorModal.js index 23aac4839d2a..3f2a05dd170c 100644 --- a/src/components/ValuePicker/ValueSelectorModal.js +++ b/src/components/ValuePicker/ValueSelectorModal.js @@ -71,6 +71,7 @@ function ValueSelectorModal({currentValue, items, selectedItem, label, isVisible sections={[{data: sectionsData}]} onSelectRow={onItemSelected} initiallyFocusedOptionKey={currentValue} + shouldStopPropagation /> diff --git a/src/hooks/useKeyboardShortcut.js b/src/hooks/useKeyboardShortcut.js index b8e297c966ed..d42727f5fb4a 100644 --- a/src/hooks/useKeyboardShortcut.js +++ b/src/hooks/useKeyboardShortcut.js @@ -21,6 +21,7 @@ export default function useKeyboardShortcut(shortcut, callback, config = {}) { // Hence the use of CONST.EMPTY_ARRAY. excludedNodes = CONST.EMPTY_ARRAY, isActive = true, + shouldStopPropagation =false } = config; useEffect(() => { @@ -35,8 +36,9 @@ export default function useKeyboardShortcut(shortcut, callback, config = {}) { priority, shouldPreventDefault, excludedNodes, + shouldStopPropagation, ); } return () => {}; - }, [isActive, callback, captureOnInputs, excludedNodes, priority, shortcut.descriptionKey, shortcut.modifiers, shortcut.shortcutKey, shouldBubble, shouldPreventDefault]); + }, [isActive, callback, captureOnInputs, excludedNodes, priority, shortcut.descriptionKey, shortcut.modifiers, shortcut.shortcutKey, shouldBubble, shouldPreventDefault, shouldStopPropagation]); } diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js index 7b1cb00a408b..f4c5d24b0302 100644 --- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js +++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js @@ -42,7 +42,9 @@ function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEven if (callback.shouldPreventDefault) { event.preventDefault(); } - + if (callback.shouldStopPropagation) { + event.stopPropagation(); + } // If the event should not bubble, short-circuit the loop return shouldBubble; }); diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index bce65744801c..1fc2c3b276ec 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -116,9 +116,10 @@ function getPlatformEquivalentForKeys(keys) { * @param {Number} [priority] The position the callback should take in the stack. 0 means top priority, and 1 means less priority than the most recently added. * @param {Boolean} [shouldPreventDefault] Should call event.preventDefault after callback? * @param {Array} [excludedNodes] Do not capture key events targeting excluded nodes (i.e. do not prevent default and let the event bubble) + * @param {Boolean} [shouldStopPropagation] Should call event.stopPropagation after callback? * @returns {Function} clean up method */ -function subscribe(key, callback, descriptionKey, modifiers = 'shift', captureOnInputs = false, shouldBubble = false, priority = 0, shouldPreventDefault = true, excludedNodes = []) { +function subscribe(key, callback, descriptionKey, modifiers = 'shift', captureOnInputs = false, shouldBubble = false, priority = 0, shouldPreventDefault = true, excludedNodes = [], shouldStopPropagation = false) { const platformAdjustedModifiers = getPlatformEquivalentForKeys(modifiers); const displayName = getDisplayName(key, platformAdjustedModifiers); if (!_.has(eventHandlers, displayName)) { @@ -133,6 +134,7 @@ function subscribe(key, callback, descriptionKey, modifiers = 'shift', captureOn shouldPreventDefault, shouldBubble, excludedNodes, + shouldStopPropagation, }); if (descriptionKey) { From 9bc0018282ec3ba9a4cdd0c973a07c4958a8704a Mon Sep 17 00:00:00 2001 From: Victor Nyagudi Date: Wed, 25 Oct 2023 09:49:05 +0300 Subject: [PATCH 065/128] Change error text color to red if the message type is 'error' --- src/components/DotIndicatorMessage.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index fc4d74339d6e..cb72a22d065c 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -57,19 +57,21 @@ function DotIndicatorMessage(props) { .map((message) => Localize.translateIfPhraseKey(message)) .value(); + const isErrorMessageType = props.type === 'error'; + return ( {_.map(sortedMessages, (message, i) => ( {message} From 39472e668950c79180686265e914a410fbd2dc82 Mon Sep 17 00:00:00 2001 From: Victor Nyagudi Date: Wed, 25 Oct 2023 10:08:52 +0300 Subject: [PATCH 066/128] Rename isErrorMessageType to isErrorMessage --- src/components/DotIndicatorMessage.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index cb72a22d065c..762ff5ddcad2 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -57,21 +57,21 @@ function DotIndicatorMessage(props) { .map((message) => Localize.translateIfPhraseKey(message)) .value(); - const isErrorMessageType = props.type === 'error'; + const isErrorMessage = props.type === 'error'; return ( {_.map(sortedMessages, (message, i) => ( {message} From 06a6f2745b0c67a07ebd35a6a24fbb0539b37458 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Wed, 25 Oct 2023 12:12:47 +0200 Subject: [PATCH 067/128] Fix ref issue --- src/components/Form/InputWrapper.js | 3 ++- src/pages/settings/Wallet/AddDebitCardPage.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Form/InputWrapper.js b/src/components/Form/InputWrapper.js index 43064b5a6690..ab087b079e1f 100644 --- a/src/components/Form/InputWrapper.js +++ b/src/components/Form/InputWrapper.js @@ -1,12 +1,13 @@ import React, {forwardRef, useContext} from 'react'; import PropTypes from 'prop-types'; import FormContext from './FormContext'; +import refPropTypes from "../refPropTypes"; const propTypes = { InputComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.elementType]).isRequired, inputID: PropTypes.string.isRequired, valueType: PropTypes.string, - forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]), + forwardedRef: refPropTypes, }; const defaultProps = { diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index b9ea0ac6df3a..0ba631148070 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -129,7 +129,7 @@ function DebitCardPage(props) { label={translate('addDebitCardPage.nameOnCard')} accessibilityLabel={translate('addDebitCardPage.nameOnCard')} accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT} - ref={(ref) => (nameOnCardRef.current = ref)} + ref={nameOnCardRef} spellCheck={false} /> Date: Wed, 25 Oct 2023 12:19:47 +0200 Subject: [PATCH 068/128] Fix listLoader issue --- src/components/AddressSearch/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index a4f712435af3..59dd6c2c658d 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -369,7 +369,7 @@ function AddressSearch({ [isTyping, translate, network.isOffline], ); - const listLoader = useMemo( + const listLoader = useCallback( () => ( Date: Wed, 25 Oct 2023 21:35:47 +0530 Subject: [PATCH 069/128] set setupComplete false --- src/libs/actions/PaymentMethods.ts | 2 +- src/pages/settings/Wallet/AddDebitCardPage.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts index fe1b5ebe10e9..9884f39b23de 100644 --- a/src/libs/actions/PaymentMethods.ts +++ b/src/libs/actions/PaymentMethods.ts @@ -214,7 +214,7 @@ function clearDebitCardFormErrorAndSubmit() { Onyx.set(ONYXKEYS.FORMS.ADD_DEBIT_CARD_FORM, { isLoading: false, errors: undefined, - setupComplete: true, + setupComplete: false, }); } diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index e75c3b2c517e..bf01cfcbebec 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -47,6 +47,10 @@ function DebitCardPage(props) { useEffect(() => { PaymentMethods.clearDebitCardFormErrorAndSubmit(); + + return () => { + PaymentMethods.clearDebitCardFormErrorAndSubmit(); + }; }, []); useEffect(() => { @@ -55,10 +59,6 @@ function DebitCardPage(props) { } PaymentMethods.continueSetup(); - - return () => { - PaymentMethods.clearDebitCardFormErrorAndSubmit(); - }; }, [prevFormDataSetupComplete, props.formData.setupComplete]); /** From f89f3419692a52940ac42c905ad4e66f0c8c0e14 Mon Sep 17 00:00:00 2001 From: Pujan Date: Wed, 25 Oct 2023 21:38:10 +0530 Subject: [PATCH 070/128] pass default value to form CheckboxWithLabel --- src/pages/settings/Wallet/AddDebitCardPage.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index bf01cfcbebec..8eb464a0d80a 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -194,6 +194,7 @@ function DebitCardPage(props) {
)} style={[styles.mt4]} + defaultValue={false} /> From d7ffb4717798771d53f3a193633bfd3ffb0bc8e7 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Thu, 26 Oct 2023 12:16:05 +0200 Subject: [PATCH 071/128] fix ref assignment --- src/pages/tasks/NewTaskTitlePage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/tasks/NewTaskTitlePage.js b/src/pages/tasks/NewTaskTitlePage.js index 2a8d776eaefd..ac4cc69bd716 100644 --- a/src/pages/tasks/NewTaskTitlePage.js +++ b/src/pages/tasks/NewTaskTitlePage.js @@ -99,7 +99,7 @@ function NewTaskTitlePage(props) { InputComponent={TextInput} accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT} defaultValue={props.task.title} - ref={(el) => (inputRef.current = el)} + ref={inputRef} inputID="taskTitle" label={props.translate('task.title')} accessibilityLabel={props.translate('task.title')} From 3472ec10339b4c6f2bc7a22ede8492c8940e045d Mon Sep 17 00:00:00 2001 From: cooldev900 Date: Thu, 26 Oct 2023 06:28:30 -0500 Subject: [PATCH 072/128] fix: show amount in confirmation page --- src/components/MoneyRequestConfirmationList.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index 0b266351a60c..e1f51bb918ba 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -321,6 +321,9 @@ function MoneyRequestConfirmationList(props) { text = translate('iou.split'); } else if ((props.receiptPath && isTypeRequest) || isDistanceRequestWithoutRoute) { text = translate('iou.request'); + if (props.iouAmount !== 0) { + text = translate('iou.requestAmount', { amount: formattedAmount }); + } } else { const translationKey = isSplitBill ? 'iou.splitAmount' : 'iou.requestAmount'; text = translate(translationKey, {amount: formattedAmount}); From 1ffa1d02bdaddb05f42a3ff3a8024d17cb46851f Mon Sep 17 00:00:00 2001 From: Kailash Devrari Date: Thu, 26 Oct 2023 18:56:45 +0530 Subject: [PATCH 073/128] prettier fixes --- .../SelectionList/selectionListPropTypes.js | 2 +- src/hooks/useKeyboardShortcut.js | 16 ++++++++++++++-- src/libs/KeyboardShortcut/index.js | 13 ++++++++++++- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/components/SelectionList/selectionListPropTypes.js b/src/components/SelectionList/selectionListPropTypes.js index a0fb36bee917..f92cdf7dd837 100644 --- a/src/components/SelectionList/selectionListPropTypes.js +++ b/src/components/SelectionList/selectionListPropTypes.js @@ -169,7 +169,7 @@ const propTypes = { showConfirmButton: PropTypes.bool, /** Whether to stop automatic form submission on pressing enter key or not */ - shouldStopPropagation : PropTypes.bool, + shouldStopPropagation: PropTypes.bool, /** Whether to prevent default focusing of options and focus the textinput when selecting an option */ shouldPreventDefaultFocusOnSelectRow: PropTypes.bool, diff --git a/src/hooks/useKeyboardShortcut.js b/src/hooks/useKeyboardShortcut.js index d42727f5fb4a..684da41c7b59 100644 --- a/src/hooks/useKeyboardShortcut.js +++ b/src/hooks/useKeyboardShortcut.js @@ -21,7 +21,7 @@ export default function useKeyboardShortcut(shortcut, callback, config = {}) { // Hence the use of CONST.EMPTY_ARRAY. excludedNodes = CONST.EMPTY_ARRAY, isActive = true, - shouldStopPropagation =false + shouldStopPropagation = false, } = config; useEffect(() => { @@ -40,5 +40,17 @@ export default function useKeyboardShortcut(shortcut, callback, config = {}) { ); } return () => {}; - }, [isActive, callback, captureOnInputs, excludedNodes, priority, shortcut.descriptionKey, shortcut.modifiers, shortcut.shortcutKey, shouldBubble, shouldPreventDefault, shouldStopPropagation]); + }, [ + isActive, + callback, + captureOnInputs, + excludedNodes, + priority, + shortcut.descriptionKey, + shortcut.modifiers, + shortcut.shortcutKey, + shouldBubble, + shouldPreventDefault, + shouldStopPropagation, + ]); } diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js index 1fc2c3b276ec..e430e076ccd8 100644 --- a/src/libs/KeyboardShortcut/index.js +++ b/src/libs/KeyboardShortcut/index.js @@ -119,7 +119,18 @@ function getPlatformEquivalentForKeys(keys) { * @param {Boolean} [shouldStopPropagation] Should call event.stopPropagation after callback? * @returns {Function} clean up method */ -function subscribe(key, callback, descriptionKey, modifiers = 'shift', captureOnInputs = false, shouldBubble = false, priority = 0, shouldPreventDefault = true, excludedNodes = [], shouldStopPropagation = false) { +function subscribe( + key, + callback, + descriptionKey, + modifiers = 'shift', + captureOnInputs = false, + shouldBubble = false, + priority = 0, + shouldPreventDefault = true, + excludedNodes = [], + shouldStopPropagation = false, +) { const platformAdjustedModifiers = getPlatformEquivalentForKeys(modifiers); const displayName = getDisplayName(key, platformAdjustedModifiers); if (!_.has(eventHandlers, displayName)) { From 8dfc203d3c9f09887e93e12e12106318fa5a7245 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 26 Oct 2023 16:33:22 +0200 Subject: [PATCH 074/128] Merge fixes --- src/components/AddressSearch/index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index 016826349b6f..3754102337b2 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -415,6 +415,16 @@ function AddressSearch({ listEmptyComponent={listEmptyComponent} listLoaderComponent={listLoader} renderHeaderComponent={renderHeaderComponent} + renderRow={(data) => { + const title = data.isPredefinedPlace ? data.name : data.structured_formatting.main_text; + const subtitle = data.isPredefinedPlace ? data.description : data.structured_formatting.secondary_text; + return ( + + {title && {title}} + {subtitle} + + ); + }} onPress={(data, details) => { saveLocationDetails(data, details); setIsTyping(false); From 211934d5b754aca11b2d7c0f992ba8253f8aff04 Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 26 Oct 2023 16:56:00 +0200 Subject: [PATCH 075/128] Fix too early error message --- src/components/Form/FormProvider.js | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js index add58dbef18c..82a92d9d5974 100644 --- a/src/components/Form/FormProvider.js +++ b/src/components/Form/FormProvider.js @@ -71,6 +71,8 @@ const propTypes = { shouldValidateOnChange: PropTypes.bool, }; +const VALIDATE_DELAY = 200; + const defaultProps = { isSubmitButtonVisible: true, formState: { @@ -240,19 +242,26 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC // as this is already happening by the value prop. defaultValue: undefined, onTouched: (event) => { - setTouchedInput(inputID); - if (_.isFunction(propsToParse.onTouched)) { + setTimeout(() => { + setTouchedInput(inputID); + }, VALIDATE_DELAY); if (_.isFunction(propsToParse.onTouched)) { propsToParse.onTouched(event); } }, onPress: (event) => { - setTouchedInput(inputID); - if (_.isFunction(propsToParse.onPress)) { + setTimeout(() => { + setTouchedInput(inputID); + }, VALIDATE_DELAY); if (_.isFunction(propsToParse.onPress)) { propsToParse.onPress(event); } }, - onPressIn: (event) => { - setTouchedInput(inputID); + onPressOut: (event) => { + // To prevent validating just pressed inputs, we need to set the touched input right after + // onValidate and to do so, we need to delays setTouchedInput of the same amount of time + // as the onValidate is delayed + setTimeout(() => { + setTouchedInput(inputID); + }, VALIDATE_DELAY); if (_.isFunction(propsToParse.onPressIn)) { propsToParse.onPressIn(event); } @@ -268,7 +277,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC if (shouldValidateOnBlur) { onValidate(inputValues, !hasServerError); } - }, 200); + }, VALIDATE_DELAY); } if (_.isFunction(propsToParse.onBlur)) { From 284f8e2547bec7ce37aeefc30c23da30ddca0840 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:05:07 +0200 Subject: [PATCH 076/128] pass correct forwardedRef types --- src/components/Form/InputWrapper.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Form/InputWrapper.js b/src/components/Form/InputWrapper.js index 43064b5a6690..576af712beaa 100644 --- a/src/components/Form/InputWrapper.js +++ b/src/components/Form/InputWrapper.js @@ -1,12 +1,13 @@ import React, {forwardRef, useContext} from 'react'; import PropTypes from 'prop-types'; import FormContext from './FormContext'; +import refPropTypes from '../refPropTypes'; const propTypes = { InputComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.elementType]).isRequired, inputID: PropTypes.string.isRequired, valueType: PropTypes.string, - forwardedRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({current: PropTypes.instanceOf(React.Component)})]), + forwardedRef: refPropTypes, }; const defaultProps = { From 674a0dcba8026f859585a43b724a21243ae7df2a Mon Sep 17 00:00:00 2001 From: Kamil Owczarz Date: Thu, 26 Oct 2023 17:48:51 +0200 Subject: [PATCH 077/128] Fix prettier --- src/components/AddressSearch/index.js | 8 ++++---- src/components/Form/FormProvider.js | 8 +++++--- src/components/Form/InputWrapper.js | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index 3754102337b2..734839ccc4d2 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -419,10 +419,10 @@ function AddressSearch({ const title = data.isPredefinedPlace ? data.name : data.structured_formatting.main_text; const subtitle = data.isPredefinedPlace ? data.description : data.structured_formatting.secondary_text; return ( - - {title && {title}} - {subtitle} - + + {title && {title}} + {subtitle} + ); }} onPress={(data, details) => { diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js index 82a92d9d5974..52cd5cddf137 100644 --- a/src/components/Form/FormProvider.js +++ b/src/components/Form/FormProvider.js @@ -244,14 +244,16 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC onTouched: (event) => { setTimeout(() => { setTouchedInput(inputID); - }, VALIDATE_DELAY); if (_.isFunction(propsToParse.onTouched)) { + }, VALIDATE_DELAY); + if (_.isFunction(propsToParse.onTouched)) { propsToParse.onTouched(event); } }, onPress: (event) => { setTimeout(() => { setTouchedInput(inputID); - }, VALIDATE_DELAY); if (_.isFunction(propsToParse.onPress)) { + }, VALIDATE_DELAY); + if (_.isFunction(propsToParse.onPress)) { propsToParse.onPress(event); } }, @@ -260,7 +262,7 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC // onValidate and to do so, we need to delays setTouchedInput of the same amount of time // as the onValidate is delayed setTimeout(() => { - setTouchedInput(inputID); + setTouchedInput(inputID); }, VALIDATE_DELAY); if (_.isFunction(propsToParse.onPressIn)) { propsToParse.onPressIn(event); diff --git a/src/components/Form/InputWrapper.js b/src/components/Form/InputWrapper.js index ab7326673ebc..249221335148 100644 --- a/src/components/Form/InputWrapper.js +++ b/src/components/Form/InputWrapper.js @@ -1,7 +1,7 @@ import React, {forwardRef, useContext} from 'react'; import PropTypes from 'prop-types'; import FormContext from './FormContext'; -import refPropTypes from "../refPropTypes"; +import refPropTypes from '../refPropTypes'; const propTypes = { InputComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.elementType]).isRequired, From a97a4a2478eabf6211456ec5b95c0025f135c3c2 Mon Sep 17 00:00:00 2001 From: Hans Date: Fri, 27 Oct 2023 00:37:01 +0700 Subject: [PATCH 078/128] fix skeleton animation on web --- config/webpack/webpack.common.js | 1 - src/components/CurrentUserPersonalDetailsSkeletonView/index.js | 2 +- src/components/MoneyRequestSkeletonView.js | 2 +- src/components/OptionsListSkeletonView.js | 2 +- src/components/ReportActionsSkeletonView/SkeletonViewLines.js | 2 +- src/components/ReportHeaderSkeletonView.js | 2 +- src/components/SkeletonViewContentLoader/index.js | 3 +++ src/components/SkeletonViewContentLoader/index.native.js | 3 +++ 8 files changed, 11 insertions(+), 6 deletions(-) create mode 100644 src/components/SkeletonViewContentLoader/index.js create mode 100644 src/components/SkeletonViewContentLoader/index.native.js diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index d8a24adefdc3..48983eddba39 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -187,7 +187,6 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({ 'react-native-config': 'react-web-config', 'react-native$': '@expensify/react-native-web', 'react-native-web': '@expensify/react-native-web', - 'react-content-loader/native': 'react-content-loader', 'lottie-react-native': 'react-native-web-lottie', }, diff --git a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js index cc305a628820..da9bb4cbc6f5 100644 --- a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js +++ b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import _ from 'underscore'; -import SkeletonViewContentLoader from 'react-content-loader/native'; import {Circle, Rect} from 'react-native-svg'; import {View} from 'react-native'; import * as StyleUtils from '../../styles/StyleUtils'; @@ -9,6 +8,7 @@ import CONST from '../../CONST'; import themeColors from '../../styles/themes/default'; import variables from '../../styles/variables'; import styles from '../../styles/styles'; +import SkeletonViewContentLoader from '../SkeletonViewContentLoader'; const propTypes = { /** Whether to animate the skeleton view */ diff --git a/src/components/MoneyRequestSkeletonView.js b/src/components/MoneyRequestSkeletonView.js index 50a7b56b91e3..f94274975fd3 100644 --- a/src/components/MoneyRequestSkeletonView.js +++ b/src/components/MoneyRequestSkeletonView.js @@ -1,9 +1,9 @@ import React from 'react'; import {Rect} from 'react-native-svg'; -import SkeletonViewContentLoader from 'react-content-loader/native'; import variables from '../styles/variables'; import themeColors from '../styles/themes/default'; import styles from '../styles/styles'; +import SkeletonViewContentLoader from './SkeletonViewContentLoader'; function MoneyRequestSkeletonView() { return ( diff --git a/src/components/OptionsListSkeletonView.js b/src/components/OptionsListSkeletonView.js index 15c66affe84d..7dd5f717f93f 100644 --- a/src/components/OptionsListSkeletonView.js +++ b/src/components/OptionsListSkeletonView.js @@ -2,10 +2,10 @@ import React from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import {Rect, Circle} from 'react-native-svg'; -import SkeletonViewContentLoader from 'react-content-loader/native'; import CONST from '../CONST'; import themeColors from '../styles/themes/default'; import styles from '../styles/styles'; +import SkeletonViewContentLoader from './SkeletonViewContentLoader'; const propTypes = { /** Whether to animate the skeleton view */ diff --git a/src/components/ReportActionsSkeletonView/SkeletonViewLines.js b/src/components/ReportActionsSkeletonView/SkeletonViewLines.js index e4432ceb2309..ae68d1bbf89a 100644 --- a/src/components/ReportActionsSkeletonView/SkeletonViewLines.js +++ b/src/components/ReportActionsSkeletonView/SkeletonViewLines.js @@ -1,10 +1,10 @@ import React from 'react'; import PropTypes from 'prop-types'; import {Rect, Circle} from 'react-native-svg'; -import SkeletonViewContentLoader from 'react-content-loader/native'; import CONST from '../../CONST'; import themeColors from '../../styles/themes/default'; import styles from '../../styles/styles'; +import SkeletonViewContentLoader from '../SkeletonViewContentLoader'; const propTypes = { /** Number of rows to show in Skeleton UI block */ diff --git a/src/components/ReportHeaderSkeletonView.js b/src/components/ReportHeaderSkeletonView.js index 5f2d5379419d..ec5f6697ef0f 100644 --- a/src/components/ReportHeaderSkeletonView.js +++ b/src/components/ReportHeaderSkeletonView.js @@ -1,7 +1,6 @@ import React from 'react'; import {View} from 'react-native'; import {Rect, Circle} from 'react-native-svg'; -import SkeletonViewContentLoader from 'react-content-loader/native'; import PropTypes from 'prop-types'; import styles from '../styles/styles'; import Icon from './Icon'; @@ -13,6 +12,7 @@ import PressableWithFeedback from './Pressable/PressableWithFeedback'; import compose from '../libs/compose'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import CONST from '../CONST'; +import SkeletonViewContentLoader from './SkeletonViewContentLoader'; const propTypes = { ...windowDimensionsPropTypes, diff --git a/src/components/SkeletonViewContentLoader/index.js b/src/components/SkeletonViewContentLoader/index.js new file mode 100644 index 000000000000..335611c6f5cb --- /dev/null +++ b/src/components/SkeletonViewContentLoader/index.js @@ -0,0 +1,3 @@ +import SkeletonViewContentLoader from 'react-content-loader'; + +export default SkeletonViewContentLoader; diff --git a/src/components/SkeletonViewContentLoader/index.native.js b/src/components/SkeletonViewContentLoader/index.native.js new file mode 100644 index 000000000000..bdcea964e52c --- /dev/null +++ b/src/components/SkeletonViewContentLoader/index.native.js @@ -0,0 +1,3 @@ +import SkeletonViewContentLoader from 'react-content-loader/native'; + +export default SkeletonViewContentLoader; From 9a40d7d2e87733ad12158e09361bf7d07f982e0b Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 27 Oct 2023 10:07:01 +0700 Subject: [PATCH 079/128] generate error when request money failure --- src/libs/actions/IOU.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index 714ea7b9aa9f..d191d934fe5e 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -345,6 +345,7 @@ function buildOnyxDataForMoneyRequest( : { [reportPreviewAction.reportActionID]: { created: reportPreviewAction.created, + errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'), }, }), }, From fde0fa6cd168d550759d534fa37bde7265a6be45 Mon Sep 17 00:00:00 2001 From: dukenv0307 Date: Fri, 27 Oct 2023 11:48:59 +0700 Subject: [PATCH 080/128] fix: update isLoading in floating action button --- .../sidebar/SidebarScreen/FloatingActionButtonAndPopover.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js index 340e7a0ed6a8..c6bee17dc10f 100644 --- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js +++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js @@ -281,7 +281,7 @@ export default compose( key: ONYXKEYS.BETAS, }, isLoading: { - key: ONYXKEYS.IS_LOADING_REPORT_DATA, + key: ONYXKEYS.IS_LOADING_APP, }, demoInfo: { key: ONYXKEYS.DEMO_INFO, From fbccf71aabb87e4d2e2756d573c2871b89f5249c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 10:12:45 +0200 Subject: [PATCH 081/128] add cooldown period --- tests/e2e/config.js | 3 +++ tests/e2e/testRunner.js | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/tests/e2e/config.js b/tests/e2e/config.js index 3b1856ab8ad8..d723682f79c1 100644 --- a/tests/e2e/config.js +++ b/tests/e2e/config.js @@ -46,6 +46,9 @@ module.exports = { // The time in milliseconds after which an operation fails due to timeout INTERACTION_TIMEOUT: 300000, + // Period we wait between each test runs, to let the device cool down + COOL_DOWN: 90 * 1000, + TEST_NAMES, /** diff --git a/tests/e2e/testRunner.js b/tests/e2e/testRunner.js index 5c6c33bdf7e9..9bdbdfe8efe8 100644 --- a/tests/e2e/testRunner.js +++ b/tests/e2e/testRunner.js @@ -250,6 +250,15 @@ const runTests = async () => { } } testLog.done(); + + // If we still have tests add a cool down period + if (testIndex < numOfTests - 1) { + const coolDownLogs = Logger.progressInfo(`Cooling down for ${config.COOL_DOWN / 1000}s`); + coolDownLogs.updateText(`Cooling down for ${config.COOL_DOWN / 1000}s`); + // eslint-disable-next-line no-loop-func + await new Promise((resolve) => setTimeout(resolve, config.COOL_DOWN)); + coolDownLogs.done(); + } } // Calculate statistics and write them to our work file From 50f22be3563fdfa5fef59ac3b82cce5bbea2a753 Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Fri, 27 Oct 2023 03:15:53 -0500 Subject: [PATCH 082/128] fix: set null to unread marker when there are no new messages --- src/pages/home/report/ReportActionsList.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js index 300b1921545d..de932d5b93a3 100644 --- a/src/pages/home/report/ReportActionsList.js +++ b/src/pages/home/report/ReportActionsList.js @@ -319,14 +319,19 @@ function ReportActionsList({ // Iterate through the report actions and set appropriate unread marker. // This is to avoid a warning of: // Cannot update a component (ReportActionsList) while rendering a different component (CellRenderer). + let markerFound = false; _.each(sortedReportActions, (reportAction, index) => { if (!shouldDisplayNewMarker(reportAction, index)) { return; } + markerFound = true; if (!currentUnreadMarker && currentUnreadMarker !== reportAction.reportActionID) { setCurrentUnreadMarker(reportAction.reportActionID); } }); + if (!markerFound) { + setCurrentUnreadMarker(null); + } }, [sortedReportActions, report.lastReadTime, messageManuallyMarkedUnread, shouldDisplayNewMarker, currentUnreadMarker]); const renderItem = useCallback( From 0826b1123f5f38a5b870d6818193116f522be90b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 10:19:01 +0200 Subject: [PATCH 083/128] increase threshold --- tests/e2e/compare/compare.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/compare/compare.js b/tests/e2e/compare/compare.js index 9d40ab2bf312..63d8697e4053 100644 --- a/tests/e2e/compare/compare.js +++ b/tests/e2e/compare/compare.js @@ -24,7 +24,7 @@ const PROBABILITY_CONSIDERED_SIGNIFICANCE = 0.02; * This is additional filter, in addition to probability threshold above. * Too small duration difference might be result of measurement grain of 1 ms. */ -const DURATION_DIFF_THRESHOLD_SIGNIFICANCE = 50; +const DURATION_DIFF_THRESHOLD_SIGNIFICANCE = 100; const loadFile = (path) => fs.readFile(path, 'utf8').then((data) => { From c469811033001aa5f53efca024b81b013257c9d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Fri, 27 Oct 2023 10:19:12 +0200 Subject: [PATCH 084/128] increase test runs --- tests/e2e/config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/config.js b/tests/e2e/config.js index d723682f79c1..dae35321fda3 100644 --- a/tests/e2e/config.js +++ b/tests/e2e/config.js @@ -31,7 +31,7 @@ module.exports = { SERVER_PORT: 4723, // The amount of times a test should be executed for average performance metrics - RUNS: 60, + RUNS: 80, DEFAULT_BASELINE_BRANCH: 'main', From 32ec465e9bb8ea0cb8e8c4fcfa2151bdbccccb32 Mon Sep 17 00:00:00 2001 From: Pujan Date: Fri, 27 Oct 2023 14:33:44 +0530 Subject: [PATCH 085/128] PR comments addressed --- src/pages/settings/Wallet/AddDebitCardPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index 8eb464a0d80a..bb115589fa3e 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -45,6 +45,7 @@ function DebitCardPage(props) { const prevFormDataSetupComplete = usePrevious(props.formData.setupComplete); const nameOnCardRef = useRef(null); + // Reset the form values on mount and unmount of the component useEffect(() => { PaymentMethods.clearDebitCardFormErrorAndSubmit(); @@ -194,7 +195,6 @@ function DebitCardPage(props) { )} style={[styles.mt4]} - defaultValue={false} /> From 2d570a7c521eee7308268678007c6fae6d7c7689 Mon Sep 17 00:00:00 2001 From: Pujan Date: Fri, 27 Oct 2023 15:16:58 +0530 Subject: [PATCH 086/128] comment updated --- src/pages/settings/Wallet/AddDebitCardPage.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index bb115589fa3e..80d1a899a9bb 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -45,7 +45,9 @@ function DebitCardPage(props) { const prevFormDataSetupComplete = usePrevious(props.formData.setupComplete); const nameOnCardRef = useRef(null); - // Reset the form values on mount and unmount of the component + /** + * Reset the form values on mount and unmount of the component to Make sure we reset the onyx values so old errors don't show if this form is displayed later + */ useEffect(() => { PaymentMethods.clearDebitCardFormErrorAndSubmit(); From 94f6b4fb925e1d4eaf510eb790033d0435d02f0a Mon Sep 17 00:00:00 2001 From: Pujan Date: Fri, 27 Oct 2023 18:23:42 +0530 Subject: [PATCH 087/128] comment change --- src/pages/settings/Wallet/AddDebitCardPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index 80d1a899a9bb..a3b59c0e7c6a 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -46,7 +46,7 @@ function DebitCardPage(props) { const nameOnCardRef = useRef(null); /** - * Reset the form values on mount and unmount of the component to Make sure we reset the onyx values so old errors don't show if this form is displayed later + * Reset the form values on the mount and unmount so that old errors don't show when this form is displayed again. */ useEffect(() => { PaymentMethods.clearDebitCardFormErrorAndSubmit(); From ed9707a3f0df9e812b50f8345be0a33ea2495ff8 Mon Sep 17 00:00:00 2001 From: Justin Persaud Date: Fri, 27 Oct 2023 16:55:10 -0400 Subject: [PATCH 088/128] Change hostname to dev.new.expensify.com --- README.md | 6 +++--- config/webpack/webpack.dev.js | 2 +- contributingGuides/APPLE_GOOGLE_SIGNIN.md | 4 ++-- desktop/main.js | 4 ++-- desktop/start.js | 2 +- docs/_includes/CONST.html | 2 +- package.json | 2 +- src/CONST.ts | 2 +- src/libs/Navigation/linkingConfig.js | 2 +- tests/unit/ReportUtilsTest.js | 2 +- 10 files changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 46eb240e310b..fdbf82df381c 100644 --- a/README.md +++ b/README.md @@ -36,9 +36,9 @@ These instructions should get you set up ready to work on New Expensify ๐Ÿ™Œ 2. Install `watchman`: `brew install watchman` 3. Install dependencies: `npm install` 4. Install `mkcert`: `brew install mkcert` followed by `npm run setup-https`. If you are not using macOS, follow the instructions [here](https://github.com/FiloSottile/mkcert?tab=readme-ov-file#installation). -5. Create a host entry in your local hosts file, `/etc/hosts` for new.expensify.com.dev pointing to localhost: +5. Create a host entry in your local hosts file, `/etc/hosts` for dev.new.expensify.com pointing to localhost: ``` -127.0.0.1 new.expensify.com.dev +127.0.0.1 dev.new.expensify.com ``` You can use any IDE or code editing tool for developing on any platform. Use your favorite! @@ -133,7 +133,7 @@ Note - If you want to run app on `https://127.0.0.1:8082`, then just install the 2. Select the emulator you want to run if prompted. (If single emulator is available, then it will open automatically) 3. Let the script execute till the message `๐ŸŽ‰ Done!`. -Note - If you want to run app on `https://new.expensify.com.dev:8082`, then just do the Android flow and use `npm run startAndroidEmulator` to start the Android Emulator every time (It will configure the emulator). +Note - If you want to run app on `https://dev.new.expensify.com:8082`, then just do the Android flow and use `npm run startAndroidEmulator` to start the Android Emulator every time (It will configure the emulator). Possible Scenario: diff --git a/config/webpack/webpack.dev.js b/config/webpack/webpack.dev.js index dcca84ce5e9d..e28383eff557 100644 --- a/config/webpack/webpack.dev.js +++ b/config/webpack/webpack.dev.js @@ -44,7 +44,7 @@ module.exports = (env = {}) => ...proxySettings, historyApiFallback: true, port, - host: 'new.expensify.com.dev', + host: 'dev.new.expensify.com', server: { type: 'https', options: { diff --git a/contributingGuides/APPLE_GOOGLE_SIGNIN.md b/contributingGuides/APPLE_GOOGLE_SIGNIN.md index 3a1feac073db..3ade13554bd6 100644 --- a/contributingGuides/APPLE_GOOGLE_SIGNIN.md +++ b/contributingGuides/APPLE_GOOGLE_SIGNIN.md @@ -161,10 +161,10 @@ function beginAppleSignIn(idToken) { You can use any SSH tunneling service that allows you to configure custom subdomains so that we have a consistent address to use. We'll use ngrok in these examples, but ngrok requires a paid account for this. If you need a free option, try serveo.net. -After you've set ngrok up to be able to run on your machine (requires configuring a key with the command line tool, instructions provided by the ngrok website after you create an account), test hosting the web app on a custom subdomain. This example assumes the development web app is running at `new.expensify.com.dev:8082`: +After you've set ngrok up to be able to run on your machine (requires configuring a key with the command line tool, instructions provided by the ngrok website after you create an account), test hosting the web app on a custom subdomain. This example assumes the development web app is running at `dev.new.expensify.com:8082`: ``` -ngrok http 8082 --host-header="new.expensify.com.dev:8082" --subdomain=mysubdomain +ngrok http 8082 --host-header="dev.new.expensify.com:8082" --subdomain=mysubdomain ``` The `--host-header` flag is there to avoid webpack errors with header validation. In addition, add `allowedHosts: 'all'` to the dev server config in `webpack.dev.js`: diff --git a/desktop/main.js b/desktop/main.js index 4b43ff128f65..7ab8d748b541 100644 --- a/desktop/main.js +++ b/desktop/main.js @@ -85,7 +85,7 @@ _.assign(console, log.functions); // until it detects that it has been upgraded to the correct version. const EXPECTED_UPDATE_VERSION_FLAG = '--expected-update-version'; -const APP_DOMAIN = __DEV__ ? `https://new.expensify.com.dev:${port}` : 'app://-'; +const APP_DOMAIN = __DEV__ ? `https://dev.new.expensify.com:${port}` : 'app://-'; let expectedUpdateVersion; for (let i = 0; i < process.argv.length; i++) { @@ -221,7 +221,7 @@ const mainWindow = () => { let deeplinkUrl; let browserWindow; - const loadURL = __DEV__ ? (win) => win.loadURL(`https://new.expensify.com.dev:${port}`) : serve({directory: `${__dirname}/www`}); + const loadURL = __DEV__ ? (win) => win.loadURL(`https://dev.new.expensify.com:${port}`) : serve({directory: `${__dirname}/www`}); // Prod and staging set the icon in the electron-builder config, so only update it here for dev if (__DEV__) { diff --git a/desktop/start.js b/desktop/start.js index a9bb5a2d588d..05a1b031350d 100644 --- a/desktop/start.js +++ b/desktop/start.js @@ -32,7 +32,7 @@ portfinder env, }, { - command: `wait-port new.expensify.com.dev:${port} && npx electronmon ./desktop/dev.js`, + command: `wait-port dev.new.expensify.com:${port} && npx electronmon ./desktop/dev.js`, name: 'Electron', prefixColor: 'cyan.dim', env, diff --git a/docs/_includes/CONST.html b/docs/_includes/CONST.html index af6a14a78331..231423f10586 100644 --- a/docs/_includes/CONST.html +++ b/docs/_includes/CONST.html @@ -1,7 +1,7 @@ {% if jekyll.environment == "production" %} {% assign MAIN_SITE_URL = "https://new.expensify.com" %} {% else %} - {% assign MAIN_SITE_URL = "https://new.expensify.com.dev:8082" %} + {% assign MAIN_SITE_URL = "https://dev.new.expensify.com:8082" %} {% endif %} {% capture CONCIERGE_CHAT_URL %}{{MAIN_SITE_URL}}/concierge{% endcapture %} diff --git a/package.json b/package.json index f7f329363145..c86ae5dfe26e 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "gh-actions-unused-styles": "./.github/scripts/findUnusedKeys.sh", "workflow-test": "./workflow_tests/scripts/runWorkflowTests.sh", "workflow-test:generate": "node workflow_tests/utils/preGenerateTest.js", - "setup-https": "mkcert -install && mkcert -cert-file config/webpack/certificate.pem -key-file config/webpack/key.pem new.expensify.com.dev localhost 127.0.0.1" + "setup-https": "mkcert -install && mkcert -cert-file config/webpack/certificate.pem -key-file config/webpack/key.pem dev.new.expensify.com localhost 127.0.0.1" }, "dependencies": { "@expensify/react-native-web": "0.18.15", diff --git a/src/CONST.ts b/src/CONST.ts index c8e6fcc65e20..cc3c7e0922fd 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -448,7 +448,7 @@ const CONST = { ONFIDO_TERMS_OF_SERVICE_URL: 'https://onfido.com/terms-of-service/', // Use Environment.getEnvironmentURL to get the complete URL with port number - DEV_NEW_EXPENSIFY_URL: 'https://new.expensify.com.dev:', + DEV_NEW_EXPENSIFY_URL: 'https://dev.new.expensify.com:', SIGN_IN_FORM_WIDTH: 300, diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 1e695fa9dcee..86c3e67cab24 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -4,7 +4,7 @@ import CONST from '../../CONST'; import NAVIGATORS from '../../NAVIGATORS'; export default { - prefixes: ['new-expensify://', 'https://www.expensify.cash', 'https://staging.expensify.cash', 'https://new.expensify.com.dev', CONST.NEW_EXPENSIFY_URL, CONST.STAGING_NEW_EXPENSIFY_URL], + prefixes: ['new-expensify://', 'https://www.expensify.cash', 'https://staging.expensify.cash', 'https://dev.new.expensify.com', CONST.NEW_EXPENSIFY_URL, CONST.STAGING_NEW_EXPENSIFY_URL], config: { initialRouteName: SCREENS.HOME, screens: { diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js index 9ddf9b93f8d0..40a0ea31ce89 100644 --- a/tests/unit/ReportUtilsTest.js +++ b/tests/unit/ReportUtilsTest.js @@ -503,7 +503,7 @@ describe('ReportUtils', () => { expect(ReportUtils.getReportIDFromLink('new-expensify://r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://www.expensify.cash/r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://staging.new.expensify.com/r/75431276')).toBe('75431276'); - expect(ReportUtils.getReportIDFromLink('https://new.expensify.com.dev/r/75431276')).toBe('75431276'); + expect(ReportUtils.getReportIDFromLink('https://dev.new.expensify.com/r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://staging.expensify.cash/r/75431276')).toBe('75431276'); expect(ReportUtils.getReportIDFromLink('https://new.expensify.com/r/75431276')).toBe('75431276'); }); From 096f0d2f6583b8e0516e5d52c11dfe32551828bb Mon Sep 17 00:00:00 2001 From: cooldev900 Date: Fri, 27 Oct 2023 17:33:25 -0500 Subject: [PATCH 089/128] fix: prettier linting --- src/components/MoneyRequestConfirmationList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js index e1f51bb918ba..83f2446686c9 100755 --- a/src/components/MoneyRequestConfirmationList.js +++ b/src/components/MoneyRequestConfirmationList.js @@ -322,7 +322,7 @@ function MoneyRequestConfirmationList(props) { } else if ((props.receiptPath && isTypeRequest) || isDistanceRequestWithoutRoute) { text = translate('iou.request'); if (props.iouAmount !== 0) { - text = translate('iou.requestAmount', { amount: formattedAmount }); + text = translate('iou.requestAmount', {amount: formattedAmount}); } } else { const translationKey = isSplitBill ? 'iou.splitAmount' : 'iou.requestAmount'; From a48b5ce52e5d5cd5c8b477fffe24e6f7ebbf047a Mon Sep 17 00:00:00 2001 From: Victor Nyagudi Date: Sat, 28 Oct 2023 13:54:22 +0300 Subject: [PATCH 090/128] Create helper method to style red dot error text --- src/components/DotIndicatorMessage.js | 3 ++- .../LocationErrorMessage/BaseLocationErrorMessage.js | 5 +++-- src/styles/StyleUtils.ts | 8 ++++++++ 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index 762ff5ddcad2..05006e05686b 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import {View} from 'react-native'; import styles from '../styles/styles'; import stylePropTypes from '../styles/stylePropTypes'; +import * as StyleUtils from '../styles/StyleUtils'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import themeColors from '../styles/themes/default'; @@ -71,7 +72,7 @@ function DotIndicatorMessage(props) { {_.map(sortedMessages, (message, i) => ( {message} diff --git a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js b/src/components/LocationErrorMessage/BaseLocationErrorMessage.js index 3a638f3e999e..03dc1fe3913a 100644 --- a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js +++ b/src/components/LocationErrorMessage/BaseLocationErrorMessage.js @@ -4,6 +4,7 @@ import {View} from 'react-native'; import CONST from '../../CONST'; import colors from '../../styles/colors'; import styles from '../../styles/styles'; +import * as StyleUtils from '../../styles/StyleUtils'; import Icon from '../Icon'; import * as Expensicons from '../Icon/Expensicons'; import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback'; @@ -42,14 +43,14 @@ function BaseLocationErrorMessage({onClose, onAllowLocationLinkPress, locationEr {isPermissionDenied ? ( - {`${translate('location.permissionDenied')} ${translate('location.please')}`} + {`${translate('location.permissionDenied')} ${translate('location.please')}`} {` ${translate('location.allowPermission')} `} - {translate('location.tryAgain')} + {translate('location.tryAgain')} ) : ( {translate('location.notFound')} diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts index 48100b2efb60..c0988875b994 100644 --- a/src/styles/StyleUtils.ts +++ b/src/styles/StyleUtils.ts @@ -1316,6 +1316,13 @@ function getTransparentColor(color: string) { return `${color}00`; } +/** + * Get the styles of the text next to dot indicators + */ +function getDotIndicatorTextStyles(isErrorText: boolean = true): TextStyle { + return isErrorText ? {...styles.offlineFeedback.text, color: styles.formError.color} : {...styles.offlineFeedback.text}; +} + export { combineStyles, displayIfTrue, @@ -1361,6 +1368,7 @@ export { getDirectionStyle, getDisabledLinkStyles, getDropDownButtonHeight, + getDotIndicatorTextStyles, getEmojiPickerListHeight, getEmojiPickerStyle, getEmojiReactionBubbleStyle, From 8cfc2d5b20f3183778dec2ac44b397080a36fb66 Mon Sep 17 00:00:00 2001 From: Victor Nyagudi Date: Sat, 28 Oct 2023 14:07:54 +0300 Subject: [PATCH 091/128] Remove unnecessary type annotation --- src/styles/StyleUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts index c0988875b994..540db0a04cd1 100644 --- a/src/styles/StyleUtils.ts +++ b/src/styles/StyleUtils.ts @@ -1319,7 +1319,7 @@ function getTransparentColor(color: string) { /** * Get the styles of the text next to dot indicators */ -function getDotIndicatorTextStyles(isErrorText: boolean = true): TextStyle { +function getDotIndicatorTextStyles(isErrorText = true): TextStyle { return isErrorText ? {...styles.offlineFeedback.text, color: styles.formError.color} : {...styles.offlineFeedback.text}; } From b992aed61ea0170b1bd6ad784c673546caa40fea Mon Sep 17 00:00:00 2001 From: Victor Nyagudi Date: Sat, 28 Oct 2023 14:20:12 +0300 Subject: [PATCH 092/128] Run prettier for prettier diff --- src/styles/StyleUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts index 540db0a04cd1..fa3c3571ebc1 100644 --- a/src/styles/StyleUtils.ts +++ b/src/styles/StyleUtils.ts @@ -1317,7 +1317,7 @@ function getTransparentColor(color: string) { } /** - * Get the styles of the text next to dot indicators + * Get the styles of the text next to dot indicators */ function getDotIndicatorTextStyles(isErrorText = true): TextStyle { return isErrorText ? {...styles.offlineFeedback.text, color: styles.formError.color} : {...styles.offlineFeedback.text}; From bf0a9128bcebed1c63123c8c5aff2f682846c3a9 Mon Sep 17 00:00:00 2001 From: Kailash Devrari Date: Sat, 28 Oct 2023 18:58:46 +0530 Subject: [PATCH 093/128] updated code because of TS changes --- src/libs/KeyboardShortcut/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/KeyboardShortcut/index.ts b/src/libs/KeyboardShortcut/index.ts index 3109ccda8aaf..65d50b403060 100644 --- a/src/libs/KeyboardShortcut/index.ts +++ b/src/libs/KeyboardShortcut/index.ts @@ -13,6 +13,7 @@ type EventHandler = { shouldPreventDefault: boolean; shouldBubble: boolean | (() => void); excludedNodes: string[]; + shouldStopPropagation: boolean; }; // Handlers for the various keyboard listeners we set up @@ -135,6 +136,7 @@ function subscribe( priority = 0, shouldPreventDefault = true, excludedNodes = [], + shouldStopPropagation = false, ) { const platformAdjustedModifiers = getPlatformEquivalentForKeys(modifiers); const displayName = getDisplayName(key, platformAdjustedModifiers); @@ -150,6 +152,7 @@ function subscribe( shouldPreventDefault, shouldBubble, excludedNodes, + shouldStopPropagation, }); if (descriptionKey) { From f497b162945fbe9e37b130b923192f758a9ab401 Mon Sep 17 00:00:00 2001 From: Victor Nyagudi Date: Sun, 29 Oct 2023 00:21:15 +0300 Subject: [PATCH 094/128] Run prettier to fix diffs --- src/components/DotIndicatorMessage.js | 2 +- src/components/LocationErrorMessage/BaseLocationErrorMessage.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/DotIndicatorMessage.js b/src/components/DotIndicatorMessage.js index afeaf68c35cc..26e01f0eee8a 100644 --- a/src/components/DotIndicatorMessage.js +++ b/src/components/DotIndicatorMessage.js @@ -1,11 +1,11 @@ import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; -import * as StyleUtils from '@styles/StyleUtils'; import _ from 'underscore'; import * as Localize from '@libs/Localize'; import stylePropTypes from '@styles/stylePropTypes'; import styles from '@styles/styles'; +import * as StyleUtils from '@styles/StyleUtils'; import themeColors from '@styles/themes/default'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; diff --git a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js b/src/components/LocationErrorMessage/BaseLocationErrorMessage.js index 7c812d1864a4..b5114acaa36b 100644 --- a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js +++ b/src/components/LocationErrorMessage/BaseLocationErrorMessage.js @@ -1,7 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; -import * as StyleUtils from '@styles/StyleUtils'; import Icon from '@components/Icon'; import * as Expensicons from '@components/Icon/Expensicons'; import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback'; @@ -11,6 +10,7 @@ import Tooltip from '@components/Tooltip'; import withLocalize, {withLocalizePropTypes} from '@components/withLocalize'; import colors from '@styles/colors'; import styles from '@styles/styles'; +import * as StyleUtils from '@styles/StyleUtils'; import CONST from '@src/CONST'; import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes'; From de3bd56392d84359931cbba77efd572042735914 Mon Sep 17 00:00:00 2001 From: Hans Date: Sun, 29 Oct 2023 15:28:39 +0700 Subject: [PATCH 095/128] fix linting --- .../CurrentUserPersonalDetailsSkeletonView/index.js | 7 +++---- src/components/MoneyRequestSkeletonView.js | 2 +- src/components/OptionsListSkeletonView.js | 9 ++++----- .../ReportActionsSkeletonView/SkeletonViewLines.js | 5 ++--- src/components/ReportHeaderSkeletonView.js | 11 +++++------ 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js index 94bca720dbd0..d56153cce1d3 100644 --- a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js +++ b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { View } from 'react-native'; -import { Circle, Rect } from 'react-native-svg'; +import {View} from 'react-native'; +import {Circle, Rect} from 'react-native-svg'; import _ from 'underscore'; import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; import styles from '@styles/styles'; @@ -10,7 +10,6 @@ import themeColors from '@styles/themes/default'; import variables from '@styles/variables'; import CONST from '@src/CONST'; - const propTypes = { /** Whether to animate the skeleton view */ shouldAnimate: PropTypes.bool, @@ -72,4 +71,4 @@ function CurrentUserPersonalDetailsSkeletonView(props) { CurrentUserPersonalDetailsSkeletonView.displayName = 'CurrentUserPersonalDetailsSkeletonView'; CurrentUserPersonalDetailsSkeletonView.propTypes = propTypes; CurrentUserPersonalDetailsSkeletonView.defaultProps = defaultProps; -export default CurrentUserPersonalDetailsSkeletonView; \ No newline at end of file +export default CurrentUserPersonalDetailsSkeletonView; diff --git a/src/components/MoneyRequestSkeletonView.js b/src/components/MoneyRequestSkeletonView.js index 7ac1640f1ebc..32eb8fef222b 100644 --- a/src/components/MoneyRequestSkeletonView.js +++ b/src/components/MoneyRequestSkeletonView.js @@ -3,7 +3,7 @@ import {Rect} from 'react-native-svg'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; import variables from '@styles/variables'; -import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; +import SkeletonViewContentLoader from './SkeletonViewContentLoader'; function MoneyRequestSkeletonView() { return ( diff --git a/src/components/OptionsListSkeletonView.js b/src/components/OptionsListSkeletonView.js index 4b014121b9e7..24783604e39a 100644 --- a/src/components/OptionsListSkeletonView.js +++ b/src/components/OptionsListSkeletonView.js @@ -1,12 +1,11 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { View } from 'react-native'; -import { Circle, Rect } from 'react-native-svg'; -import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; +import {View} from 'react-native'; +import {Circle, Rect} from 'react-native-svg'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; import CONST from '@src/CONST'; - +import SkeletonViewContentLoader from './SkeletonViewContentLoader'; const propTypes = { /** Whether to animate the skeleton view */ @@ -109,4 +108,4 @@ class OptionsListSkeletonView extends React.Component { OptionsListSkeletonView.propTypes = propTypes; OptionsListSkeletonView.defaultProps = defaultTypes; -export default OptionsListSkeletonView; \ No newline at end of file +export default OptionsListSkeletonView; diff --git a/src/components/ReportActionsSkeletonView/SkeletonViewLines.js b/src/components/ReportActionsSkeletonView/SkeletonViewLines.js index 15d05ff2f30b..51ae4c1034a5 100644 --- a/src/components/ReportActionsSkeletonView/SkeletonViewLines.js +++ b/src/components/ReportActionsSkeletonView/SkeletonViewLines.js @@ -1,12 +1,11 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { Circle, Rect } from 'react-native-svg'; +import {Circle, Rect} from 'react-native-svg'; import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; import CONST from '@src/CONST'; - const propTypes = { /** Number of rows to show in Skeleton UI block */ numberOfRows: PropTypes.number.isRequired, @@ -66,4 +65,4 @@ function SkeletonViewLines(props) { SkeletonViewLines.displayName = 'SkeletonViewLines'; SkeletonViewLines.propTypes = propTypes; SkeletonViewLines.defaultProps = defaultTypes; -export default SkeletonViewLines; \ No newline at end of file +export default SkeletonViewLines; diff --git a/src/components/ReportHeaderSkeletonView.js b/src/components/ReportHeaderSkeletonView.js index 56d022bca151..6d2a8e343e3b 100644 --- a/src/components/ReportHeaderSkeletonView.js +++ b/src/components/ReportHeaderSkeletonView.js @@ -1,8 +1,7 @@ import PropTypes from 'prop-types'; import React from 'react'; -import { View } from 'react-native'; -import { Circle, Rect } from 'react-native-svg'; -import SkeletonViewContentLoader from '@components/SkeletonViewContentLoader'; +import {View} from 'react-native'; +import {Circle, Rect} from 'react-native-svg'; import compose from '@libs/compose'; import styles from '@styles/styles'; import themeColors from '@styles/themes/default'; @@ -11,9 +10,9 @@ import CONST from '@src/CONST'; import Icon from './Icon'; import * as Expensicons from './Icon/Expensicons'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; +import SkeletonViewContentLoader from './SkeletonViewContentLoader'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; -import withWindowDimensions, { windowDimensionsPropTypes } from './withWindowDimensions'; - +import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; const propTypes = { ...windowDimensionsPropTypes, @@ -72,4 +71,4 @@ function ReportHeaderSkeletonView(props) { ReportHeaderSkeletonView.propTypes = propTypes; ReportHeaderSkeletonView.defaultProps = defaultProps; ReportHeaderSkeletonView.displayName = 'ReportHeaderSkeletonView'; -export default compose(withWindowDimensions, withLocalize)(ReportHeaderSkeletonView); \ No newline at end of file +export default compose(withWindowDimensions, withLocalize)(ReportHeaderSkeletonView); From 7bbc8411c2c34dd4efbde7e5b3f7effa7e3fd83b Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Sun, 29 Oct 2023 23:40:21 +0530 Subject: [PATCH 096/128] input of '[' and other special characters fixed --- src/libs/convertToLTRForComposer/index.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libs/convertToLTRForComposer/index.ts b/src/libs/convertToLTRForComposer/index.ts index 37015a755869..c11f90054083 100644 --- a/src/libs/convertToLTRForComposer/index.ts +++ b/src/libs/convertToLTRForComposer/index.ts @@ -1,4 +1,4 @@ -import CONST from '@src/CONST'; +import CONST from '../../CONST'; import ConvertToLTRForComposer from './types'; function hasRTLCharacters(text: string): boolean { @@ -9,10 +9,11 @@ function hasRTLCharacters(text: string): boolean { // Converts a given text to ensure it starts with the LTR (Left-to-Right) marker. const convertToLTRForComposer: ConvertToLTRForComposer = (text) => { - // Ensure that the text starts with RTL characters if not we return the same text to avoid concatination with special character at the start which leads to unexpected behaviour for Emoji/Mention suggestions. + // Ensure that the text starts with RTL characters if not we return the same text to avoid concatination with special + // character at the start which leads to unexpected behaviour for Emoji/Mention suggestions. if (!hasRTLCharacters(text)) { // If text is empty string return empty string to avoid an empty draft due to special character. - if (text === '' || CONST.UNICODE.LTR.match(text)) { + if (text === '' || text.startsWith(CONST.UNICODE.LTR)) { return ''; } return text; From cca1382c56bfb1f37145e59fd4a60d22efa615b1 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Sun, 29 Oct 2023 19:46:36 +0100 Subject: [PATCH 097/128] Fix lint problems for Environment lib --- src/libs/Environment/getEnvironment/index.native.ts | 2 +- src/libs/Environment/getEnvironment/index.ts | 2 +- src/libs/Environment/getEnvironment/types.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/Environment/getEnvironment/index.native.ts b/src/libs/Environment/getEnvironment/index.native.ts index 7d15bb17a625..766f288376b5 100644 --- a/src/libs/Environment/getEnvironment/index.native.ts +++ b/src/libs/Environment/getEnvironment/index.native.ts @@ -1,7 +1,7 @@ import Config from 'react-native-config'; -import Environment from './types'; import betaChecker from '@libs/Environment/betaChecker'; import CONST from '@src/CONST'; +import Environment from './types'; let environment: Environment | null = null; diff --git a/src/libs/Environment/getEnvironment/index.ts b/src/libs/Environment/getEnvironment/index.ts index d6c475d2b356..84f64e91649b 100644 --- a/src/libs/Environment/getEnvironment/index.ts +++ b/src/libs/Environment/getEnvironment/index.ts @@ -1,6 +1,6 @@ import Config from 'react-native-config'; -import Environment from './types'; import CONST from '@src/CONST'; +import Environment from './types'; function getEnvironment(): Promise { return Promise.resolve((Config?.ENVIRONMENT as Environment) ?? CONST.ENVIRONMENT.DEV); diff --git a/src/libs/Environment/getEnvironment/types.ts b/src/libs/Environment/getEnvironment/types.ts index 7cf17af3e0d8..9247ed17ffe2 100644 --- a/src/libs/Environment/getEnvironment/types.ts +++ b/src/libs/Environment/getEnvironment/types.ts @@ -1,5 +1,5 @@ import {ValueOf} from 'type-fest'; -import CONST from '../../../CONST'; +import CONST from '@src/CONST'; type Environment = ValueOf; From 91dcf2b6920f70223c16cf422662c36e865a4206 Mon Sep 17 00:00:00 2001 From: Bartosz Grajdek Date: Sun, 29 Oct 2023 19:51:28 +0100 Subject: [PATCH 098/128] Resolve prettier error --- src/libs/ApiUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/ApiUtils.ts b/src/libs/ApiUtils.ts index d66cde3f4eed..3d7347136897 100644 --- a/src/libs/ApiUtils.ts +++ b/src/libs/ApiUtils.ts @@ -1,5 +1,5 @@ -import {ValueOf} from 'type-fest'; import Onyx from 'react-native-onyx'; +import {ValueOf} from 'type-fest'; import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; From c1453334504f0aa68bb2f2035138f6a4220defa1 Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 00:24:28 +0530 Subject: [PATCH 099/128] lint error fixed --- src/libs/convertToLTRForComposer/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/convertToLTRForComposer/index.ts b/src/libs/convertToLTRForComposer/index.ts index c11f90054083..a985a5640d1a 100644 --- a/src/libs/convertToLTRForComposer/index.ts +++ b/src/libs/convertToLTRForComposer/index.ts @@ -1,4 +1,4 @@ -import CONST from '../../CONST'; +import CONST from '@src/CONST'; import ConvertToLTRForComposer from './types'; function hasRTLCharacters(text: string): boolean { From c4cc9715d484dfadd69e66142f9b24cd239e79b1 Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 00:48:13 +0530 Subject: [PATCH 100/128] suggested changes applied --- src/libs/convertToLTRForComposer/index.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libs/convertToLTRForComposer/index.ts b/src/libs/convertToLTRForComposer/index.ts index a985a5640d1a..dd6ee50d862e 100644 --- a/src/libs/convertToLTRForComposer/index.ts +++ b/src/libs/convertToLTRForComposer/index.ts @@ -13,10 +13,7 @@ const convertToLTRForComposer: ConvertToLTRForComposer = (text) => { // character at the start which leads to unexpected behaviour for Emoji/Mention suggestions. if (!hasRTLCharacters(text)) { // If text is empty string return empty string to avoid an empty draft due to special character. - if (text === '' || text.startsWith(CONST.UNICODE.LTR)) { - return ''; - } - return text; + return text.replace(CONST.UNICODE.LTR, ''); } // Check if the text contains only spaces. If it does, we do not concatenate it with CONST.UNICODE.LTR, From ca2b3e2ba77fe350c7c2c8012aaf5aae02747eb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 30 Oct 2023 09:50:06 +0100 Subject: [PATCH 101/128] fix e2e tests after eslint/prettier import changes --- .prettierignore | 2 ++ src/libs/E2E/reactNativeLaunchingTest.js | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.prettierignore b/.prettierignore index 5f6292b551c1..80888b18a317 100644 --- a/.prettierignore +++ b/.prettierignore @@ -15,3 +15,5 @@ package-lock.json *.css *.scss *.md +# We need to modify the import here specifically, hence we disable prettier to get rid of the sorted imports +src/libs/E2E/reactNativeLaunchingTest.js diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js index 1e0d6a8afa3b..7621e462f8c5 100644 --- a/src/libs/E2E/reactNativeLaunchingTest.js +++ b/src/libs/E2E/reactNativeLaunchingTest.js @@ -7,7 +7,6 @@ */ import * as Metrics from '@libs/Metrics'; import Performance from '@libs/Performance'; -import '../../../index'; import E2EConfig from '../../../tests/e2e/config'; import E2EClient from './client'; @@ -65,5 +64,5 @@ E2EClient.getTestConfig() // start the usual app Performance.markStart('regularAppStart'); - +import '../../../index'; Performance.markEnd('regularAppStart'); From f42c5794d5abe90031b391bdf9aaad6a02b337e8 Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Wed, 25 Oct 2023 15:44:35 -0300 Subject: [PATCH 102/128] Add new method formatWithUTCTimeZone to format the date using the UTC timezone --- src/libs/DateUtils.ts | 20 +++++++++++++++++++- tests/unit/DateUtilsTest.js | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index e03e3dd55680..8012f0217722 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -8,13 +8,14 @@ import { isBefore, isSameDay, isSameYear, + isValid, setDefaultOptions, startOfWeek, subDays, subMilliseconds, subMinutes, } from 'date-fns'; -import {formatInTimeZone, utcToZonedTime, zonedTimeToUtc} from 'date-fns-tz'; +import {formatInTimeZone, utcToZonedTime, zonedTimeToUtc, format as tzFormat} from 'date-fns-tz'; import {enGB, es} from 'date-fns/locale'; import throttle from 'lodash/throttle'; import Onyx from 'react-native-onyx'; @@ -335,6 +336,22 @@ function getStatusUntilDate(inputDate: string): string { return translateLocal('statusPage.untilTime', {time: format(input, `${CONST.DATE.FNS_FORMAT_STRING} ${CONST.DATE.LOCAL_TIME_FORMAT}`)}); } +/** + * Get a date and format this date using the UTC timezone. + * @param datetime + * @param dateFormat + * @returns If the date is valid, returns the formatted date with the UTC timezone, otherwise returns an empty string. + */ +function formatWithUTCTimeZone(datetime: string, dateFormat: string = CONST.DATE.FNS_FORMAT_STRING) { + const date = new Date(datetime); + + if (isValid(date)) { + return tzFormat(utcToZonedTime(date, 'UTC'), dateFormat); + } + + return ''; +} + const DateUtils = { formatToDayOfWeek, formatToLongDateWithWeekday, @@ -356,6 +373,7 @@ const DateUtils = { isToday, isTomorrow, isYesterday, + formatWithUTCTimeZone, }; export default DateUtils; diff --git a/tests/unit/DateUtilsTest.js b/tests/unit/DateUtilsTest.js index 4b76e0f496c8..0303085f1172 100644 --- a/tests/unit/DateUtilsTest.js +++ b/tests/unit/DateUtilsTest.js @@ -182,4 +182,30 @@ describe('DateUtils', () => { expect(getDBTime).toBe('2022-11-22 03:14:10.792'); }); }); + + describe('formatWithUTCTimeZone', () => { + describe('when the date is invalid', () => { + it('returns an empty string', () => { + const invalidDateStr = ''; + + const formattedDate = DateUtils.formatWithUTCTimeZone(invalidDateStr); + + expect(formattedDate).toEqual(''); + }); + }); + + describe('when the date is valid', () => { + const scenarios = [ + {dateFormat: CONST.DATE.FNS_FORMAT_STRING, expectedResult: '2022-11-07'}, + {dateFormat: CONST.DATE.FNS_TIMEZONE_FORMAT_STRING, expectedResult: '2022-11-07T00:00:00Z'}, + {dateFormat: CONST.DATE.FNS_DB_FORMAT_STRING, expectedResult: '2022-11-07 00:00:00.000'}, + ]; + + test.each(scenarios)('returns the date as string with the format "$dateFormat"', ({dateFormat, expectedResult}) => { + const formattedDate = DateUtils.formatWithUTCTimeZone(datetime, dateFormat); + + expect(formattedDate).toEqual(expectedResult); + }); + }); + }); }); From cb4d259a4ddce924d910c9fb885dde1906e0524c Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Wed, 25 Oct 2023 16:20:24 -0300 Subject: [PATCH 103/128] Refactor getCreated method to use the method formatWithUTCTimeZone from DateUtils to format the created date --- src/libs/DateUtils.ts | 4 +- src/libs/TransactionUtils.ts | 13 ++---- tests/unit/TransactionUtilsTest.ts | 64 ++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 tests/unit/TransactionUtilsTest.ts diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 8012f0217722..bed4f079cd03 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -22,8 +22,8 @@ import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {Timezone} from '@src/types/onyx/PersonalDetails'; -import * as CurrentDate from './actions/CurrentDate'; -import * as Localize from './Localize'; +import * as CurrentDate from '@libs/actions/CurrentDate'; +import * as Localize from '@libs/Localize'; let currentUserAccountID: number | undefined; Onyx.connect({ diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index a30ba7fc2723..e6517de0b43b 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -1,12 +1,11 @@ -import {format, isValid} from 'date-fns'; import Onyx, {OnyxCollection} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {RecentWaypoint, ReportAction, Transaction} from '@src/types/onyx'; import {Comment, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; -import {isExpensifyCard} from './CardUtils'; -import DateUtils from './DateUtils'; -import * as NumberUtils from './NumberUtils'; +import {isExpensifyCard} from '@libs/CardUtils'; +import DateUtils from '@libs/DateUtils'; +import * as NumberUtils from '@libs/NumberUtils'; type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; @@ -310,12 +309,8 @@ function getTag(transaction: Transaction): string { */ function getCreated(transaction: Transaction, dateFormat: string = CONST.DATE.FNS_FORMAT_STRING): string { const created = transaction?.modifiedCreated ? transaction.modifiedCreated : transaction?.created || ''; - const createdDate = new Date(created); - if (isValid(createdDate)) { - return format(createdDate, dateFormat); - } - return ''; + return DateUtils.formatWithUTCTimeZone(created, dateFormat); } function isDistanceRequest(transaction: Transaction): boolean { diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts new file mode 100644 index 000000000000..89514e3b6671 --- /dev/null +++ b/tests/unit/TransactionUtilsTest.ts @@ -0,0 +1,64 @@ +import type {Transaction} from '../../src/types/onyx'; +import * as TransactionUtils from '../../src/libs/TransactionUtils'; + +function generateTransaction(values: Partial = {}): Transaction { + const reportID = '1'; + const amount = 100; + const currency = 'USD'; + const comment = ''; + const created = '2023-10-01'; + const baseValues = TransactionUtils.buildOptimisticTransaction(amount, currency, reportID, comment, created); + + return {...baseValues, ...values}; +} + +describe('TransactionUtils', () => { + describe('getCreated', () => { + describe('when the transaction property "modifiedCreated" has value', () => { + const transaction = generateTransaction({ + created: '2023-10-01', + modifiedCreated: '2023-10-25', + }); + + it('returns the "modifiedCreated" date with the correct format', () => { + const expectedResult = '2023-10-25'; + + const result = TransactionUtils.getCreated(transaction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the transaction property "modifiedCreated" does not have value', () => { + describe('and the transaction property "created" has value', () => { + const transaction = generateTransaction({ + created: '2023-10-01', + modifiedCreated: undefined, + }); + + it('returns the "created" date with the correct format', () => { + const expectedResult = '2023-10-01'; + + const result = TransactionUtils.getCreated(transaction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('and the transaction property "created" does not have value', () => { + const transaction = generateTransaction({ + created: undefined, + modifiedCreated: undefined, + }); + + it('returns an empty string', () => { + const expectedResult = ''; + + const result = TransactionUtils.getCreated(transaction); + + expect(result).toEqual(expectedResult); + }); + }); + }); + }); +}); From bb8e3c3042dbc42e4186f9141fdf69b73b91a941 Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Thu, 26 Oct 2023 00:09:51 -0300 Subject: [PATCH 104/128] Fix Prettier issues --- tests/unit/TransactionUtilsTest.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index 89514e3b6671..c00337404333 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -46,19 +46,19 @@ describe('TransactionUtils', () => { }); describe('and the transaction property "created" does not have value', () => { - const transaction = generateTransaction({ - created: undefined, - modifiedCreated: undefined, - }); + const transaction = generateTransaction({ + created: undefined, + modifiedCreated: undefined, + }); - it('returns an empty string', () => { - const expectedResult = ''; + it('returns an empty string', () => { + const expectedResult = ''; - const result = TransactionUtils.getCreated(transaction); + const result = TransactionUtils.getCreated(transaction); - expect(result).toEqual(expectedResult); - }); - }); + expect(result).toEqual(expectedResult); + }); + }); }); }); }); From fadff382ed05b264ac746cc391c0f9a48f726c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hanno=20J=2E=20G=C3=B6decke?= Date: Mon, 30 Oct 2023 11:04:17 +0100 Subject: [PATCH 105/128] prevent babel from failing when CAPTURE_METRICS true --- babel.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/babel.config.js b/babel.config.js index 189c3379aa6d..7de6926c850d 100644 --- a/babel.config.js +++ b/babel.config.js @@ -98,6 +98,7 @@ if (process.env.CAPTURE_METRICS === 'true') { 'scheduler/tracing': 'scheduler/tracing-profiling', }, }, + 'extra-alias', ]); } From 7442875a1d7557b0ecda5459413d5d875fc5e077 Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Mon, 30 Oct 2023 07:06:40 -0300 Subject: [PATCH 106/128] fix: merge conflicts --- src/libs/DateUtils.ts | 6 +++--- src/libs/TransactionUtils.ts | 6 +++--- tests/unit/TransactionUtilsTest.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index bed4f079cd03..13853189ed26 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -15,15 +15,15 @@ import { subMilliseconds, subMinutes, } from 'date-fns'; -import {formatInTimeZone, utcToZonedTime, zonedTimeToUtc, format as tzFormat} from 'date-fns-tz'; +import {formatInTimeZone, format as tzFormat, utcToZonedTime, zonedTimeToUtc} from 'date-fns-tz'; import {enGB, es} from 'date-fns/locale'; import throttle from 'lodash/throttle'; import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {Timezone} from '@src/types/onyx/PersonalDetails'; -import * as CurrentDate from '@libs/actions/CurrentDate'; -import * as Localize from '@libs/Localize'; +import * as CurrentDate from './actions/CurrentDate'; +import * as Localize from './Localize'; let currentUserAccountID: number | undefined; Onyx.connect({ diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index e6517de0b43b..acf10042b265 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -3,9 +3,9 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {RecentWaypoint, ReportAction, Transaction} from '@src/types/onyx'; import {Comment, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; -import {isExpensifyCard} from '@libs/CardUtils'; -import DateUtils from '@libs/DateUtils'; -import * as NumberUtils from '@libs/NumberUtils'; +import {isExpensifyCard} from './CardUtils'; +import DateUtils from './DateUtils'; +import * as NumberUtils from './NumberUtils'; type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index c00337404333..e51ffede633b 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -1,5 +1,5 @@ -import type {Transaction} from '../../src/types/onyx'; import * as TransactionUtils from '../../src/libs/TransactionUtils'; +import type {Transaction} from '../../src/types/onyx'; function generateTransaction(values: Partial = {}): Transaction { const reportID = '1'; From 6a4f127c801324c30671465db236c6a2cb73be04 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:16:50 +0100 Subject: [PATCH 107/128] fix lint errors and include new import method --- src/components/AddressSearch/index.js | 5 ++--- src/components/Form/InputWrapper.js | 3 ++- src/pages/settings/Wallet/AddDebitCardPage.js | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js index 2d550623a0ad..f8219c028853 100644 --- a/src/components/AddressSearch/index.js +++ b/src/components/AddressSearch/index.js @@ -1,8 +1,7 @@ -import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; +import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; +import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react'; import {ActivityIndicator, Keyboard, LogBox, ScrollView, Text, View} from 'react-native'; -import lodashGet from 'lodash/get'; -import React, {useEffect, useMemo, useRef, useState} from 'react'; import {GooglePlacesAutocomplete} from 'react-native-google-places-autocomplete'; import _ from 'underscore'; import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator'; diff --git a/src/components/Form/InputWrapper.js b/src/components/Form/InputWrapper.js index 5a97185aa89d..c49d11a5b075 100644 --- a/src/components/Form/InputWrapper.js +++ b/src/components/Form/InputWrapper.js @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React, {forwardRef, useContext} from 'react'; -import refPropTypes from '../refPropTypes'; +import refPropTypes from '@components/refPropTypes'; import FormContext from './FormContext'; const propTypes = { @@ -14,6 +14,7 @@ const propTypes = { const defaultProps = { forwardedRef: undefined, valueType: 'string', + valueParser: () => {}, }; function InputWrapper(props) { diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js index 4dba77158653..8b8938a9ea42 100644 --- a/src/pages/settings/Wallet/AddDebitCardPage.js +++ b/src/pages/settings/Wallet/AddDebitCardPage.js @@ -1,11 +1,11 @@ +import PropTypes from 'prop-types'; import React, {useEffect, useRef} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import PropTypes from 'prop-types'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; import AddressSearch from '@components/AddressSearch'; import CheckboxWithLabel from '@components/CheckboxWithLabel'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import StatePicker from '@components/StatePicker'; From 5fd75e1c201fec2174d6b9cd039bb30e54fda05c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Ska=C5=82ka?= Date: Mon, 30 Oct 2023 11:18:09 +0100 Subject: [PATCH 108/128] fix prettier diff --- src/libs/SelectionScraper/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/SelectionScraper/index.ts b/src/libs/SelectionScraper/index.ts index 203660b56ad8..1f62f83e1c91 100644 --- a/src/libs/SelectionScraper/index.ts +++ b/src/libs/SelectionScraper/index.ts @@ -1,7 +1,7 @@ import render from 'dom-serializer'; +import {DataNode, Element, Node} from 'domhandler'; import Str from 'expensify-common/lib/str'; import {parseDocument} from 'htmlparser2'; -import {DataNode, Element, Node} from 'domhandler'; import CONST from '@src/CONST'; import GetCurrentSelection from './types'; From 055d5dad061705e5e45d138afbdcf537053e3bd4 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 11:59:42 +0100 Subject: [PATCH 109/128] fix prettier and lint --- src/components/Form/InputWrapper.js | 2 +- src/pages/tasks/NewTaskTitlePage.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/components/Form/InputWrapper.js b/src/components/Form/InputWrapper.js index 2f7ca50eccf9..b2e6f4477e89 100644 --- a/src/components/Form/InputWrapper.js +++ b/src/components/Form/InputWrapper.js @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import React, {forwardRef, useContext} from 'react'; +import refPropTypes from '@components/refPropTypes'; import FormContext from './FormContext'; -import refPropTypes from '../refPropTypes'; const propTypes = { InputComponent: PropTypes.oneOfType([PropTypes.func, PropTypes.elementType]).isRequired, diff --git a/src/pages/tasks/NewTaskTitlePage.js b/src/pages/tasks/NewTaskTitlePage.js index 6229a8f1252e..e7be9a239e5d 100644 --- a/src/pages/tasks/NewTaskTitlePage.js +++ b/src/pages/tasks/NewTaskTitlePage.js @@ -2,7 +2,8 @@ import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; -import Form from '@components/Form'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapperWithRef from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; @@ -88,7 +89,7 @@ function NewTaskTitlePage(props) { enabledWhenOffline > - Date: Mon, 30 Oct 2023 12:07:54 +0100 Subject: [PATCH 110/128] fix prettier and lint --- src/pages/tasks/NewTaskDescriptionPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/tasks/NewTaskDescriptionPage.js b/src/pages/tasks/NewTaskDescriptionPage.js index 4d1276b1fffc..0d6f03006263 100644 --- a/src/pages/tasks/NewTaskDescriptionPage.js +++ b/src/pages/tasks/NewTaskDescriptionPage.js @@ -2,6 +2,8 @@ import PropTypes from 'prop-types'; import React from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapperWithRef from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; @@ -17,8 +19,6 @@ import * as Task from '@userActions/Task'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapperWithRef from '@components/Form/InputWrapper'; const propTypes = { /** Beta features list */ From a027e642e1049b7972967a18046b7370eb9666b7 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:17:15 +0100 Subject: [PATCH 111/128] fix prettier and lint --- src/pages/EditRequestDescriptionPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EditRequestDescriptionPage.js b/src/pages/EditRequestDescriptionPage.js index e0fc33d5bdf8..d83df3a07671 100644 --- a/src/pages/EditRequestDescriptionPage.js +++ b/src/pages/EditRequestDescriptionPage.js @@ -2,6 +2,8 @@ import {useFocusEffect} from '@react-navigation/native'; import PropTypes from 'prop-types'; import React, {useCallback, useRef} from 'react'; import {View} from 'react-native'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapperWithRef from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; @@ -11,8 +13,6 @@ import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; import styles from '@styles/styles'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; -import FormProvider from '@components/Form/FormProvider'; -import InputWrapperWithRef from '@components/Form/InputWrapper'; const propTypes = { /** Transaction default description value */ From d646877d27d62ff014a885fb730de84cec211fbf Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:26:36 +0100 Subject: [PATCH 112/128] fix new import aliases --- src/pages/iou/MoneyRequestDescriptionPage.js | 33 ++++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/pages/iou/MoneyRequestDescriptionPage.js b/src/pages/iou/MoneyRequestDescriptionPage.js index 5620457c9b7f..ee6a9ae60b4a 100644 --- a/src/pages/iou/MoneyRequestDescriptionPage.js +++ b/src/pages/iou/MoneyRequestDescriptionPage.js @@ -5,23 +5,22 @@ import React, {useCallback, useEffect, useRef} from 'react'; import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; -import lodashGet from 'lodash/get'; -import {iouPropTypes, iouDefaultProps} from './propTypes'; -import TextInput from '../../components/TextInput'; -import ScreenWrapper from '../../components/ScreenWrapper'; -import HeaderWithBackButton from '../../components/HeaderWithBackButton'; -import ONYXKEYS from '../../ONYXKEYS'; -import styles from '../../styles/styles'; -import Navigation from '../../libs/Navigation/Navigation'; -import ROUTES from '../../ROUTES'; -import * as IOU from '../../libs/actions/IOU'; -import * as MoneyRequestUtils from '../../libs/MoneyRequestUtils'; -import CONST from '../../CONST'; -import useLocalize from '../../hooks/useLocalize'; -import updateMultilineInputRange from '../../libs/UpdateMultilineInputRange'; -import * as Browser from '../../libs/Browser'; -import FormProvider from '../../components/Form/FormProvider'; -import InputWrapper from '../../components/Form/InputWrapper'; +import FormProvider from '@components/Form/FormProvider'; +import InputWrapper from '@components/Form/InputWrapper'; +import HeaderWithBackButton from '@components/HeaderWithBackButton'; +import ScreenWrapper from '@components/ScreenWrapper'; +import TextInput from '@components/TextInput'; +import CONST from '@src/CONST'; +import useLocalize from '@hooks/useLocalize'; +import * as IOU from '@libs/actions/IOU'; +import * as Browser from '@libs/Browser'; +import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; +import Navigation from '@libs/Navigation/Navigation'; +import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import ONYXKEYS from '@src/ONYXKEYS'; +import ROUTES from '@src/ROUTES'; +import styles from '@styles/styles'; +import {iouDefaultProps, iouPropTypes} from './propTypes'; const propTypes = { /** Onyx Props */ From 9163bb0c5a54fd10e233607092113658ef3a4428 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:27:17 +0100 Subject: [PATCH 113/128] fix prettier --- src/pages/iou/MoneyRequestDescriptionPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/MoneyRequestDescriptionPage.js b/src/pages/iou/MoneyRequestDescriptionPage.js index ee6a9ae60b4a..2fc511cf5e36 100644 --- a/src/pages/iou/MoneyRequestDescriptionPage.js +++ b/src/pages/iou/MoneyRequestDescriptionPage.js @@ -10,16 +10,16 @@ import InputWrapper from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; -import CONST from '@src/CONST'; import useLocalize from '@hooks/useLocalize'; import * as IOU from '@libs/actions/IOU'; import * as Browser from '@libs/Browser'; import * as MoneyRequestUtils from '@libs/MoneyRequestUtils'; import Navigation from '@libs/Navigation/Navigation'; import updateMultilineInputRange from '@libs/UpdateMultilineInputRange'; +import styles from '@styles/styles'; +import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import ROUTES from '@src/ROUTES'; -import styles from '@styles/styles'; import {iouDefaultProps, iouPropTypes} from './propTypes'; const propTypes = { From dba6fbb0d8c204cea7e77fdb92940acf9f399095 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:31:49 +0100 Subject: [PATCH 114/128] fix InputWrapper ref --- src/pages/iou/MoneyRequestDescriptionPage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/iou/MoneyRequestDescriptionPage.js b/src/pages/iou/MoneyRequestDescriptionPage.js index 2fc511cf5e36..425aa313a468 100644 --- a/src/pages/iou/MoneyRequestDescriptionPage.js +++ b/src/pages/iou/MoneyRequestDescriptionPage.js @@ -6,7 +6,7 @@ import {View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import _ from 'underscore'; import FormProvider from '@components/Form/FormProvider'; -import InputWrapper from '@components/Form/InputWrapper'; +import InputWrapperWithRef from '@components/Form/InputWrapper'; import HeaderWithBackButton from '@components/HeaderWithBackButton'; import ScreenWrapper from '@components/ScreenWrapper'; import TextInput from '@components/TextInput'; @@ -124,7 +124,7 @@ function MoneyRequestDescriptionPage({iou, route, selectedTab}) { enabledWhenOffline > - Date: Mon, 30 Oct 2023 11:35:41 +0000 Subject: [PATCH 115/128] rename lastFourDigits to cardLastFourDigits for API call --- src/libs/actions/Card.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libs/actions/Card.js b/src/libs/actions/Card.js index 126608cf1b47..b3fde73aef6f 100644 --- a/src/libs/actions/Card.js +++ b/src/libs/actions/Card.js @@ -92,13 +92,13 @@ function requestReplacementExpensifyCard(cardId, reason) { /** * Activates the physical Expensify card based on the last four digits of the card number * - * @param {Number} lastFourDigits + * @param {Number} cardLastFourDigits * @param {Number} cardID */ -function activatePhysicalExpensifyCard(lastFourDigits, cardID) { +function activatePhysicalExpensifyCard(cardLastFourDigits, cardID) { API.write( 'ActivatePhysicalExpensifyCard', - {lastFourDigits, cardID}, + {cardLastFourDigits, cardID}, { optimisticData: [ { From 0f6688b2204017be697fbedc8d1a865f7134dc6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tymoteusz=20Ka=C5=82uzie=C5=84ski?= <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 12:52:47 +0100 Subject: [PATCH 116/128] Update src/components/CheckboxWithLabel.js Co-authored-by: Rajat Parashar --- src/components/CheckboxWithLabel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js index f18ec346dfa2..d8f18754c700 100644 --- a/src/components/CheckboxWithLabel.js +++ b/src/components/CheckboxWithLabel.js @@ -7,7 +7,7 @@ import variables from '@styles/variables'; import Checkbox from './Checkbox'; import FormHelpMessage from './FormHelpMessage'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; -import refPropTypes from './refPropTypes'; +import refPropTypes from '@components/refPropTypes'; import Text from './Text'; /** From b35ebf5e53165a62e27c01eb60db57572c9f761c Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 13:04:01 +0100 Subject: [PATCH 117/128] revert import to fix prettier and lint --- src/components/CheckboxWithLabel.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js index d8f18754c700..f18ec346dfa2 100644 --- a/src/components/CheckboxWithLabel.js +++ b/src/components/CheckboxWithLabel.js @@ -7,7 +7,7 @@ import variables from '@styles/variables'; import Checkbox from './Checkbox'; import FormHelpMessage from './FormHelpMessage'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; -import refPropTypes from '@components/refPropTypes'; +import refPropTypes from './refPropTypes'; import Text from './Text'; /** From 890dd5449d9d29fce8ff0cfec548acfdfd2ab262 Mon Sep 17 00:00:00 2001 From: cdOut <88325488+cdOut@users.noreply.github.com> Date: Mon, 30 Oct 2023 14:54:11 +0100 Subject: [PATCH 118/128] remove unused code --- src/components/Form/InputWrapper.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/Form/InputWrapper.js b/src/components/Form/InputWrapper.js index c49d11a5b075..b2e6f4477e89 100644 --- a/src/components/Form/InputWrapper.js +++ b/src/components/Form/InputWrapper.js @@ -8,13 +8,11 @@ const propTypes = { inputID: PropTypes.string.isRequired, valueType: PropTypes.string, forwardedRef: refPropTypes, - valueParser: PropTypes.func, }; const defaultProps = { forwardedRef: undefined, valueType: 'string', - valueParser: () => {}, }; function InputWrapper(props) { From 7054c5110906ca732d2b0ece401b27063a14db1a Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 20:13:32 +0530 Subject: [PATCH 119/128] test for convertToLTRForComposer added --- tests/unit/ConvertToLTRForComposerTest.js | 60 +++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/unit/ConvertToLTRForComposerTest.js diff --git a/tests/unit/ConvertToLTRForComposerTest.js b/tests/unit/ConvertToLTRForComposerTest.js new file mode 100644 index 000000000000..9179e8e5a479 --- /dev/null +++ b/tests/unit/ConvertToLTRForComposerTest.js @@ -0,0 +1,60 @@ +import convertToLTRForComposer from '@libs/convertToLTRForComposer'; +import CONST from '@src/CONST'; +import {platform} from 'os'; + +describe('convertToLTRForComposer', () => { + test('Input without RTL characters remains unchanged', () => { + // Test when input contains no RTL characters + const inputText = 'Hello, world!'; + const result = convertToLTRForComposer(inputText); + expect(result).toBe(inputText); + }); + + test('Input with RTL characters is prefixed with LTR marker', () => { + // Test when input contains RTL characters + const inputText = 'ู…ุซุงู„'; + const result = convertToLTRForComposer(inputText); + if (platform === 'android') { + expect(result).toBe(inputText); + } else { + expect(result).toBe(`${CONST.UNICODE.LTR}${inputText}`); + } + }); + + test('Input with only space remains unchanged', () => { + // Test when input contains only spaces + const inputText = ' '; + const result = convertToLTRForComposer(inputText); + expect(result).toBe(inputText); + }); + + test('Input with existing LTR marker remains unchanged', () => { + // Test when input already starts with the LTR marker + const inputText = `${CONST.UNICODE.LTR}ู…ุซุงู„`; + const result = convertToLTRForComposer(inputText); + expect(result).toBe(inputText); + }); + + test('Input starting with native emojis remains unchanged', () => { + // Test when input starts with the native emojis + const inputText = '๐Ÿงถ'; + const result = convertToLTRForComposer(inputText); + expect(result).toBe(inputText); + }); + + test('Input is empty', () => { + // Test when input is empty to check for draft comments + const inputText = ''; + const result = convertToLTRForComposer(inputText); + expect(result.length).toBe(0); + }); + + test('input with special characters remains unchanged', () => { + // Test when input contains special characters + const specialCharacters = ['!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '-', '=', '{', '}', '[', ']', '"', ':', ';', '<', '>', '?', '`', '~']; + specialCharacters.forEach((character) => { + const result = convertToLTRForComposer(character); + expect(result).toBe(character); + }); + }); +}); From a2c202561db88128aef0a22b655cd0d623de4742 Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 20:31:25 +0530 Subject: [PATCH 120/128] test case added --- tests/unit/ConvertToLTRForComposerTest.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/unit/ConvertToLTRForComposerTest.js b/tests/unit/ConvertToLTRForComposerTest.js index 9179e8e5a479..d0a923f9663e 100644 --- a/tests/unit/ConvertToLTRForComposerTest.js +++ b/tests/unit/ConvertToLTRForComposerTest.js @@ -21,6 +21,17 @@ describe('convertToLTRForComposer', () => { } }); + test('Input with mixed RTL and LTR characters is prefixed with LTR marker', () => { + // Test when input contains mix of RTL and LTR characters + const inputText = 'ู…ุซุงู„ test '; + const result = convertToLTRForComposer(inputText); + if (platform === 'android') { + expect(result).toBe(inputText); + } else { + expect(result).toBe(`${CONST.UNICODE.LTR}${inputText}`); + } + }); + test('Input with only space remains unchanged', () => { // Test when input contains only spaces const inputText = ' '; From c449904dc4ecee4442f3dad9c0a0dc942d7e03c4 Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 21:11:25 +0530 Subject: [PATCH 121/128] lint fixed --- tests/unit/ConvertToLTRForComposerTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/ConvertToLTRForComposerTest.js b/tests/unit/ConvertToLTRForComposerTest.js index d0a923f9663e..e978ef33b0e6 100644 --- a/tests/unit/ConvertToLTRForComposerTest.js +++ b/tests/unit/ConvertToLTRForComposerTest.js @@ -1,5 +1,5 @@ -import convertToLTRForComposer from '@libs/convertToLTRForComposer'; -import CONST from '@src/CONST'; +import convertToLTRForComposer from '../../src/libs/convertToLTRForComposer'; +import CONST from '../../src/CONST'; import {platform} from 'os'; describe('convertToLTRForComposer', () => { From 9bd0b5f8f758eaf006b72976ac21beb387e34ef4 Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 21:16:06 +0530 Subject: [PATCH 122/128] lint fixed --- tests/unit/ConvertToLTRForComposerTest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/ConvertToLTRForComposerTest.js b/tests/unit/ConvertToLTRForComposerTest.js index e978ef33b0e6..238c8d135eb6 100644 --- a/tests/unit/ConvertToLTRForComposerTest.js +++ b/tests/unit/ConvertToLTRForComposerTest.js @@ -1,6 +1,6 @@ +import {platform} from 'os'; import convertToLTRForComposer from '../../src/libs/convertToLTRForComposer'; import CONST from '../../src/CONST'; -import {platform} from 'os'; describe('convertToLTRForComposer', () => { test('Input without RTL characters remains unchanged', () => { From f6eede0ede133927ead734bdc2bb5a3689164d2f Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 21:47:55 +0530 Subject: [PATCH 123/128] OS check removed --- tests/unit/ConvertToLTRForComposerTest.js | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/tests/unit/ConvertToLTRForComposerTest.js b/tests/unit/ConvertToLTRForComposerTest.js index 238c8d135eb6..3cf08b910925 100644 --- a/tests/unit/ConvertToLTRForComposerTest.js +++ b/tests/unit/ConvertToLTRForComposerTest.js @@ -1,4 +1,3 @@ -import {platform} from 'os'; import convertToLTRForComposer from '../../src/libs/convertToLTRForComposer'; import CONST from '../../src/CONST'; @@ -14,22 +13,14 @@ describe('convertToLTRForComposer', () => { // Test when input contains RTL characters const inputText = 'ู…ุซุงู„'; const result = convertToLTRForComposer(inputText); - if (platform === 'android') { - expect(result).toBe(inputText); - } else { - expect(result).toBe(`${CONST.UNICODE.LTR}${inputText}`); - } + expect(result).toBe(`${CONST.UNICODE.LTR}${inputText}`); }); test('Input with mixed RTL and LTR characters is prefixed with LTR marker', () => { // Test when input contains mix of RTL and LTR characters const inputText = 'ู…ุซุงู„ test '; const result = convertToLTRForComposer(inputText); - if (platform === 'android') { - expect(result).toBe(inputText); - } else { - expect(result).toBe(`${CONST.UNICODE.LTR}${inputText}`); - } + expect(result).toBe(`${CONST.UNICODE.LTR}${inputText}`); }); test('Input with only space remains unchanged', () => { From d28b633bd616a76e2cd5c2f2ca2da8d7e7b106ae Mon Sep 17 00:00:00 2001 From: Hardik Choudhary Date: Mon, 30 Oct 2023 21:58:04 +0530 Subject: [PATCH 124/128] lint fixed --- tests/unit/ConvertToLTRForComposerTest.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unit/ConvertToLTRForComposerTest.js b/tests/unit/ConvertToLTRForComposerTest.js index 3cf08b910925..86246a9f1302 100644 --- a/tests/unit/ConvertToLTRForComposerTest.js +++ b/tests/unit/ConvertToLTRForComposerTest.js @@ -1,5 +1,5 @@ -import convertToLTRForComposer from '../../src/libs/convertToLTRForComposer'; -import CONST from '../../src/CONST'; +import convertToLTRForComposer from '@libs/convertToLTRForComposer'; +import CONST from '@src/CONST'; describe('convertToLTRForComposer', () => { test('Input without RTL characters remains unchanged', () => { From df585fad93c5848fdd4462f352f878908c9e3e7b Mon Sep 17 00:00:00 2001 From: Rodrigo Lino da Costa Date: Mon, 30 Oct 2023 18:00:55 +0000 Subject: [PATCH 125/128] ignoring keydown events for keys that don't have handlers subscribed --- .../bindHandlerToKeydownEvent/index.native.ts | 6 ++++++ .../KeyboardShortcut/bindHandlerToKeydownEvent/index.ts | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts index 72a4365b87e2..4f2d07fa10f0 100644 --- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts +++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts @@ -1,3 +1,4 @@ +import _ from 'underscore'; import getKeyEventModifiers from '@libs/KeyboardShortcut/getKeyEventModifiers'; import BindHandlerToKeydownEvent from './types'; @@ -8,6 +9,11 @@ const bindHandlerToKeydownEvent: BindHandlerToKeydownEvent = (getDisplayName, ev const eventModifiers = getKeyEventModifiers(keyCommandEvent); const displayName = getDisplayName(keyCommandEvent.input, eventModifiers); + // If we didn't register any event handlers for a key we ignore it + if (!eventHandlers[displayName]) { + return; + } + // Loop over all the callbacks Object.values(eventHandlers[displayName]).every((callback) => { // Determine if the event should bubble before executing the callback (which may have side-effects) diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.ts b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.ts index 8f2eaad25c5b..8992a5c997e7 100644 --- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.ts +++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.ts @@ -13,6 +13,11 @@ const bindHandlerToKeydownEvent: BindHandlerToKeydownEvent = (getDisplayName, ev const eventModifiers = getKeyEventModifiers(keyCommandEvent); const displayName = getDisplayName(keyCommandEvent.input, eventModifiers); + // If we didn't register any event handlers for a key we ignore it + if (!eventHandlers[displayName]) { + return; + } + // Loop over all the callbacks Object.values(eventHandlers[displayName]).every((callback) => { const textArea = event.target as HTMLTextAreaElement; From 186033b2fc82149ad42a92b2b132258f7f458279 Mon Sep 17 00:00:00 2001 From: Rodrigo Lino da Costa Date: Mon, 30 Oct 2023 18:09:03 +0000 Subject: [PATCH 126/128] removed unused import --- .../KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts index 4f2d07fa10f0..4deabb9aa5ef 100644 --- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts +++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts @@ -1,4 +1,3 @@ -import _ from 'underscore'; import getKeyEventModifiers from '@libs/KeyboardShortcut/getKeyEventModifiers'; import BindHandlerToKeydownEvent from './types'; From 1ea6e6d826bebc52c09eb6c1859cd780240b0c48 Mon Sep 17 00:00:00 2001 From: dkJacEne Date: Mon, 30 Oct 2023 19:12:42 +0100 Subject: [PATCH 127/128] Updated value to tostring to ensure proper casting from number values from the backend --- src/libs/TransactionUtils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index acf10042b265..2cc63e63e753 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -200,7 +200,8 @@ function getTransaction(transactionID: string): Transaction | Record Date: Mon, 30 Oct 2023 14:54:19 -0700 Subject: [PATCH 128/128] Add a basic sitemap --- docs/sitemap.xml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/sitemap.xml b/docs/sitemap.xml index 1dc57b5364fa..8b911fa849cd 100644 --- a/docs/sitemap.xml +++ b/docs/sitemap.xml @@ -1,10 +1,12 @@ +--- +layout: +--- - - + + {% assign pages = site.html_pages | where_exp:'doc','doc.sitemap != false' | where_exp:'doc','doc.url != "/404.html"' %} + {% for page in pages %} - https://help.expensify.com - 2023-07-27 - monthly - 1.0 + {{ page.url | replace:'/index.html','/' | absolute_url | xml_escape }} - + {% endfor %} + \ No newline at end of file