diff --git a/.eslintrc.js b/.eslintrc.js
index 35a4a333f8af..b76782af60f4 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -24,7 +24,7 @@ const restrictedImportPatterns = [
];
module.exports = {
- extends: ['expensify', 'plugin:storybook/recommended', 'plugin:react-hooks/recommended', 'plugin:react-native-a11y/basic', 'prettier'],
+ extends: ['expensify', 'plugin:storybook/recommended', 'plugin:react-hooks/recommended', 'plugin:react-native-a11y/basic', 'plugin:@dword-design/import-alias/recommended', 'prettier'],
plugins: ['react-hooks', 'react-native-a11y'],
parser: 'babel-eslint',
ignorePatterns: ['!.*', 'src/vendor', '.github/actions/**/index.js', 'desktop/dist/*.js', 'dist/*.js', 'node_modules/.bin/**', 'node_modules/.cache/**', '.git/**'],
@@ -49,8 +49,31 @@ module.exports = {
touchables: ['PressableWithoutFeedback', 'PressableWithFeedback'],
},
],
+ '@dword-design/import-alias/prefer-alias': [
+ 'warn',
+ {
+ alias: {
+ '@assets': './assets',
+ '@components': './src/components',
+ '@hooks': './src/hooks',
+ // This is needed up here, if not @libs/actions would take the priority
+ '@userActions': './src/libs/actions',
+ '@libs': './src/libs',
+ '@navigation': './src/libs/Navigation',
+ '@pages': './src/pages',
+ '@styles': './src/styles',
+ // This path is provide alias for files like `ONYXKEYS` and `CONST`.
+ '@src': './src',
+ },
+ },
+ ],
},
},
+ // This helps disable the `prefer-alias` rule to be enabled for specific directories
+ {
+ files: ['tests/**/*.js', 'tests/**/*.ts', 'tests/**/*.jsx', 'assets/**/*.js', '.storybook/**/*.js'],
+ rules: {'@dword-design/import-alias/prefer-alias': ['off']},
+ },
{
files: ['*.js', '*.jsx'],
settings: {
@@ -79,6 +102,7 @@ module.exports = {
},
],
curly: 'error',
+ 'react/display-name': 'error',
},
},
{
diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml
index 9a314079362c..cd19a46b6a88 100644
--- a/.github/actionlint.yaml
+++ b/.github/actionlint.yaml
@@ -3,3 +3,4 @@ self-hosted-runner:
labels:
- ubuntu-latest-xl
- macos-12-xl
+ - macos-13-xlarge
diff --git a/.github/actions/composite/buildAndroidAPK/action.yml b/.github/actions/composite/buildAndroidAPK/action.yml
index fc280ab2a223..4f466be84a68 100644
--- a/.github/actions/composite/buildAndroidAPK/action.yml
+++ b/.github/actions/composite/buildAndroidAPK/action.yml
@@ -11,7 +11,7 @@ runs:
steps:
- uses: Expensify/App/.github/actions/composite/setupNode@main
- - uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7
+ - uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011
with:
ruby-version: "2.7"
bundler-cache: true
diff --git a/.github/actions/composite/setupGitForOSBotifyApp/action.yml b/.github/actions/composite/setupGitForOSBotifyApp/action.yml
index bd5b5139bc6b..52fb097d254e 100644
--- a/.github/actions/composite/setupGitForOSBotifyApp/action.yml
+++ b/.github/actions/composite/setupGitForOSBotifyApp/action.yml
@@ -24,6 +24,21 @@ outputs:
runs:
using: composite
steps:
+ - name: Check if gpg encrypted private key is present
+ id: key_check
+ shell: bash
+ run: |
+ if [[ -f .github/workflows/OSBotify-private-key.asc.gpg ]]; then
+ echo "::set-output name=key_exists::true"
+ fi
+
+ - name: Checkout
+ uses: actions/checkout@v3
+ if: steps.key_check.outputs.key_exists != 'true'
+ with:
+ sparse-checkout: |
+ .github
+
- name: Decrypt OSBotify GPG key
run: cd .github/workflows && gpg --quiet --batch --yes --decrypt --passphrase=${{ inputs.GPG_PASSPHRASE }} --output OSBotify-private-key.asc OSBotify-private-key.asc.gpg
shell: bash
@@ -47,7 +62,7 @@ runs:
- name: Generate a token
id: generateToken
- uses: tibdex/github-app-token@3beb63f4bd073e61482598c45c71c1019b59b73a
+ uses: actions/create-github-app-token@9d97a4282b2c51a2f4f0465b9326399f53c890d4
with:
- app_id: ${{ inputs.OS_BOTIFY_APP_ID }}
- private_key: ${{ inputs.OS_BOTIFY_PRIVATE_KEY }}
+ app-id: ${{ inputs.OS_BOTIFY_APP_ID }}
+ private-key: ${{ inputs.OS_BOTIFY_PRIVATE_KEY }}
diff --git a/.github/workflows/authorChecklist.yml b/.github/workflows/authorChecklist.yml
index 33916d7bd10d..6cd881d18c29 100644
--- a/.github/workflows/authorChecklist.yml
+++ b/.github/workflows/authorChecklist.yml
@@ -9,7 +9,7 @@ jobs:
# then you also need to go into PHP and update the name of this job in the GH_JOB_NAME_CHECKLIST constant
checklist:
runs-on: ubuntu-latest
- if: github.actor != 'OSBotify'
+ if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]'
steps:
- name: authorChecklist.js
uses: Expensify/App/.github/actions/javascript/authorChecklist@main
diff --git a/.github/workflows/cla.yml b/.github/workflows/cla.yml
index 54ae1048b57b..4031d6c0c119 100644
--- a/.github/workflows/cla.yml
+++ b/.github/workflows/cla.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
# This job only runs for pull request comments or pull request target events (not issue comments)
# It does not run for pull requests created by OSBotify
- if: ${{ github.event.issue.pull_request || (github.event_name == 'pull_request_target' && github.event.pull_request.user.login != 'OSBotify') }}
+ if: ${{ github.event.issue.pull_request || (github.event_name == 'pull_request_target' && github.event.pull_request.user.login != 'OSBotify' && github.event.pull_request.user.login != 'imgbot[bot]') }}
steps:
- name: CLA comment check
uses: actions-ecosystem/action-regex-match@9c35fe9ac1840239939c59e5db8839422eed8a73
diff --git a/.github/workflows/imgbot.yml b/.github/workflows/imgbot.yml
new file mode 100644
index 000000000000..5247fad8349e
--- /dev/null
+++ b/.github/workflows/imgbot.yml
@@ -0,0 +1,25 @@
+name: imgbot Image Optimization
+
+on: pull_request
+
+permissions:
+ pull-requests: write
+ # The two permissions below are supposedly needed to allow a pull request to be merged.
+ # See https://github.com/cli/cli/discussions/6379
+ issues: write
+ contents: write
+
+jobs:
+ approveAndMerge:
+ runs-on: ubuntu-latest
+ if: ${{ github.actor == 'imgbot[bot]' }}
+ steps:
+ - name: Approve imgbot PR
+ run: gh pr review --approve "${{ github.event.pull_request.html_url }}"
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Merge imgbot PR
+ run: gh pr merge --auto --merge "${{ github.event.pull_request.html_url }}"
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index b403a1eb737c..3072b3354a84 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -5,6 +5,7 @@ on:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
+ paths: ['**.js', '**.ts', '**.tsx', '**.json', '**.mjs', '**.cjs', 'config/.editorconfig', '.watchmanconfig', '.imgbotconfig']
jobs:
lint:
@@ -12,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
+ uses: actions/checkout@v3
- name: Setup Node
uses: Expensify/App/.github/actions/composite/setupNode@main
@@ -22,9 +23,6 @@ jobs:
env:
CI: true
- - name: Lint shell scripts with ShellCheck
- run: npm run shellcheck
-
- name: Verify there's no Prettier diff
run: |
npm run prettier -- --loglevel silent
diff --git a/.github/workflows/platformDeploy.yml b/.github/workflows/platformDeploy.yml
index 1105f78da27a..d18a0a383ed6 100644
--- a/.github/workflows/platformDeploy.yml
+++ b/.github/workflows/platformDeploy.yml
@@ -67,7 +67,7 @@ jobs:
uses: Expensify/App/.github/actions/composite/setupNode@main
- name: Setup Ruby
- uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7
+ uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011
with:
ruby-version: '2.7'
bundler-cache: true
@@ -178,7 +178,7 @@ jobs:
name: Build and deploy iOS
needs: validateActor
if: ${{ fromJSON(needs.validateActor.outputs.IS_DEPLOYER) }}
- runs-on: macos-12-xl
+ runs-on: macos-13-xlarge
steps:
- name: Checkout
uses: actions/checkout@v3
@@ -190,7 +190,7 @@ jobs:
uses: Expensify/App/.github/actions/composite/setupNode@main
- name: Setup Ruby
- uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7
+ uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011
with:
ruby-version: '2.7'
bundler-cache: true
diff --git a/.github/workflows/preDeploy.yml b/.github/workflows/preDeploy.yml
index d7d372aa7948..bae843e74709 100644
--- a/.github/workflows/preDeploy.yml
+++ b/.github/workflows/preDeploy.yml
@@ -2,8 +2,8 @@ name: Process new code merged to main
on:
push:
- branches:
- - main
+ branches: [main]
+ paths-ignore: [docs/**, contributingGuides/**, jest/**, tests/**, workflow_tests/**]
jobs:
typecheck:
@@ -112,71 +112,6 @@ jobs:
with:
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
- # Check if actor is member of Expensify organization by looking for Expensify/expensify team
- isExpensifyEmployee:
- runs-on: ubuntu-latest
-
- outputs:
- IS_EXPENSIFY_EMPLOYEE: ${{ fromJSON(steps.checkAuthor.outputs.IS_EXPENSIFY_EMPLOYEE) }}
-
- steps:
- - name: Get merged pull request
- id: getMergedPullRequest
- uses: roryabraham/action-get-merged-pull-request@7a7a194f6ff8f3eef58c822083695a97314ebec1
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Check whether the PR author is member of Expensify/expensify team
- id: checkAuthor
- run: |
- if gh api /orgs/Expensify/teams/expensify-expensify/memberships/${{ steps.getMergedPullRequest.outputs.author }} --silent; then
- echo "IS_EXPENSIFY_EMPLOYEE=true" >> "$GITHUB_OUTPUT"
- else
- echo "IS_EXPENSIFY_EMPLOYEE=false" >> "$GITHUB_OUTPUT"
- fi
- env:
- GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
-
- newContributorWelcomeMessage:
- runs-on: ubuntu-latest
- needs: isExpensifyEmployee
- if: ${{ github.actor != 'OSBotify' && !fromJSON(needs.isExpensifyEmployee.outputs.IS_EXPENSIFY_EMPLOYEE) }}
- steps:
- # Version: 2.3.4
- - name: Checkout
- uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
- with:
- token: ${{ secrets.OS_BOTIFY_TOKEN }}
-
- - name: Get merged pull request
- id: getMergedPullRequest
- # TODO: Point back action actions-ecosystem after https://github.com/actions-ecosystem/action-get-merged-pull-request/pull/223 is merged
- uses: roryabraham/action-get-merged-pull-request@7a7a194f6ff8f3eef58c822083695a97314ebec1
- with:
- github_token: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Get PR count for ${{ steps.getMergedPullRequest.outputs.author }}
- run: echo "PR_COUNT=$(gh pr list --author ${{ steps.getMergedPullRequest.outputs.author }} --state any | grep -c '')" >> "$GITHUB_ENV"
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Comment on ${{ steps.getMergedPullRequest.outputs.author }}\'s first pull request!
- if: ${{ fromJSON(env.PR_COUNT) == 1 }}
- uses: actions-ecosystem/action-create-comment@cd098164398331c50e7dfdd0dfa1b564a1873fac
- with:
- github_token: ${{ secrets.OS_BOTIFY_TOKEN }}
- number: ${{ steps.getMergedPullRequest.outputs.number }}
- body: |
- @${{ steps.getMergedPullRequest.outputs.author }}, Great job getting your first Expensify/App pull request over the finish line! :tada:
-
- I know there's a lot of information in our [contributing guidelines](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md), so here are some points to take note of :memo::
-
- 1. Now that your first PR has been merged, you can be hired for another issue. Once you've completed a few issues, you may be eligible to work on more than one job at a time.
- 2. Once your PR is deployed to our staging servers, it will undergo quality assurance (QA) testing. If we find that it doesn't work as expected or causes a regression, you'll be responsible for fixing it. Typically, we would revert this PR and give you another chance to create a similar PR without causing a regression.
- 3. Once your PR is deployed to _production_, we start a 7-day timer :alarm_clock:. After it has been on production for 7 days without causing any regressions, then we pay out the Upwork job. :moneybag:
-
- So it might take a while before you're paid for your work, but we typically post multiple new jobs every day, so there's plenty of opportunity. I hope you've had a positive experience contributing to this repo! :blush:
-
e2ePerformanceTests:
needs: [chooseDeployActions]
if: ${{ needs.chooseDeployActions.outputs.SHOULD_DEPLOY }}
diff --git a/.github/workflows/reassurePerformanceTests.yml b/.github/workflows/reassurePerformanceTests.yml
index ab5e1d06e5a4..b259ff9052b6 100644
--- a/.github/workflows/reassurePerformanceTests.yml
+++ b/.github/workflows/reassurePerformanceTests.yml
@@ -4,6 +4,7 @@ on:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
+ paths-ignore: [docs/**, .github/**, contributingGuides/**, tests/**, workflow_tests/**, '**.md', '**.sh']
jobs:
perf-tests:
diff --git a/.github/workflows/reviewerChecklist.yml b/.github/workflows/reviewerChecklist.yml
index 413fc88ff403..e86e08375269 100644
--- a/.github/workflows/reviewerChecklist.yml
+++ b/.github/workflows/reviewerChecklist.yml
@@ -7,7 +7,7 @@ jobs:
# then you also need to go into PHP and update the name of this job in the GH_JOB_NAME_CHECKLIST constant
checklist:
runs-on: ubuntu-latest
- if: github.actor != 'OSBotify'
+ if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]'
steps:
- name: reviewerChecklist.js
uses: Expensify/App/.github/actions/javascript/reviewerChecklist@main
diff --git a/.github/workflows/shellCheck.yml b/.github/workflows/shellCheck.yml
new file mode 100644
index 000000000000..609541e9a660
--- /dev/null
+++ b/.github/workflows/shellCheck.yml
@@ -0,0 +1,19 @@
+name: Lint shell code
+
+on:
+ workflow_call:
+ pull_request:
+ types: [opened, synchronize]
+ branches-ignore: [staging, production]
+ paths: ['**.sh']
+
+jobs:
+ lint:
+ if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Lint shell scripts with ShellCheck
+ run: npm run shellcheck
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 72bdd0468fd2..fa47a2f61d4a 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -5,10 +5,11 @@ on:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
+ paths: ['**.js', '**.ts', '**.tsx', '**.sh', 'package.json', 'package-lock.json']
jobs:
jest:
- if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
+ if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' || github.event_name == 'workflow_call' }}
runs-on: ubuntu-latest
env:
CI: true
@@ -39,7 +40,7 @@ jobs:
run: npx jest --silent --shard=${{ fromJSON(matrix.chunk) }}/${{ strategy.job-total }} --max-workers ${{ steps.cpu-cores.outputs.count }}
storybookTests:
- if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
+ if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' || github.event_name == 'workflow_call' }}
runs-on: ubuntu-latest
name: Storybook tests
steps:
@@ -51,7 +52,7 @@ jobs:
run: npm run storybook -- --smoke-test --ci
shellTests:
- if: ${{ github.actor != 'OSBotify' || github.event_name == 'workflow_call' }}
+ if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' || github.event_name == 'workflow_call' }}
runs-on: ubuntu-latest
name: Shell tests
steps:
diff --git a/.github/workflows/testBuild.yml b/.github/workflows/testBuild.yml
index 6ded44d7059f..beb5d4e2f530 100644
--- a/.github/workflows/testBuild.yml
+++ b/.github/workflows/testBuild.yml
@@ -86,7 +86,7 @@ jobs:
uses: Expensify/App/.github/actions/composite/setupNode@main
- name: Setup Ruby
- uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7
+ uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011
with:
ruby-version: '2.7'
bundler-cache: true
@@ -133,7 +133,7 @@ jobs:
if: ${{ fromJSON(needs.validateActor.outputs.READY_TO_BUILD) }}
env:
PULL_REQUEST_NUMBER: ${{ github.event.number || github.event.inputs.PULL_REQUEST_NUMBER }}
- runs-on: macos-12-xl
+ runs-on: macos-13-xlarge
steps:
# This action checks-out the repository, so the workflow can access it.
- name: Checkout
@@ -157,7 +157,7 @@ jobs:
run: sudo xcode-select -switch /Applications/Xcode_14.2.app
- name: Setup Ruby
- uses: ruby/setup-ruby@eae47962baca661befdfd24e4d6c34ade04858f7
+ uses: ruby/setup-ruby@a05e47355e80e57b9a67566a813648fa67d92011
with:
ruby-version: '2.7'
bundler-cache: true
diff --git a/.github/workflows/typecheck.yml b/.github/workflows/typecheck.yml
index de433b2ae88a..776169fc6058 100644
--- a/.github/workflows/typecheck.yml
+++ b/.github/workflows/typecheck.yml
@@ -5,6 +5,7 @@ on:
pull_request:
types: [opened, synchronize]
branches-ignore: [staging, production]
+ paths: ['**.ts', '**.tsx', 'package.json', 'package-lock.json']
jobs:
typecheck:
diff --git a/.github/workflows/validateDocsRoutes.yml b/.github/workflows/validateDocsRoutes.yml
index 717560e19f5f..14c08e087565 100644
--- a/.github/workflows/validateDocsRoutes.yml
+++ b/.github/workflows/validateDocsRoutes.yml
@@ -8,7 +8,7 @@ on:
jobs:
verify:
- if: github.actor != 'OSBotify'
+ if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
diff --git a/.github/workflows/validateGithubActions.yml b/.github/workflows/validateGithubActions.yml
index bcda941e1b05..2d3216fefe75 100644
--- a/.github/workflows/validateGithubActions.yml
+++ b/.github/workflows/validateGithubActions.yml
@@ -9,7 +9,7 @@ on:
jobs:
verify:
- if: github.actor != 'OSBotify'
+ if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]'
runs-on: ubuntu-latest
steps:
- name: Checkout
diff --git a/.github/workflows/verifyPodfile.yml b/.github/workflows/verifyPodfile.yml
index d8d931e476d1..d98780e3e829 100644
--- a/.github/workflows/verifyPodfile.yml
+++ b/.github/workflows/verifyPodfile.yml
@@ -11,7 +11,7 @@ on:
jobs:
verify:
- if: github.actor != 'OSBotify'
+ if: github.actor != 'OSBotify' && github.actor != 'imgbot[bot]'
runs-on: macos-latest
steps:
- name: Checkout
diff --git a/.github/workflows/welcome.yml b/.github/workflows/welcome.yml
new file mode 100644
index 000000000000..43e0e1650381
--- /dev/null
+++ b/.github/workflows/welcome.yml
@@ -0,0 +1,55 @@
+name: Post new contributor welcome message
+
+on:
+ push:
+ branches: [main]
+
+jobs:
+ newContributorWelcomeMessage:
+ runs-on: ubuntu-latest
+ if: ${{ github.actor != 'OSBotify' && github.actor != 'imgbot[bot]' }}
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Get merged pull request
+ id: getMergedPullRequest
+ run: |
+ read -r number author < <(gh pr list --search ${{ github.sha }} --state merged --json 'number,author' | jq -r '.[0] | [.number, .author.login] | join(" ")')
+ echo "number=$number" >> "$GITHUB_OUTPUT"
+ echo "author=$author" >> "$GITHUB_OUTPUT"
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+
+ - name: Check whether the PR author is member of Expensify/expensify team
+ id: isExpensifyEmployee
+ run: |
+ if gh api /orgs/Expensify/teams/expensify-expensify/memberships/${{ steps.getMergedPullRequest.outputs.author }} --silent; then
+ echo "IS_EXPENSIFY_EMPLOYEE=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "IS_EXPENSIFY_EMPLOYEE=false" >> "$GITHUB_OUTPUT"
+ fi
+ env:
+ GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
+
+ - name: Get PR count for ${{ steps.getMergedPullRequest.outputs.author }}
+ id: getPRCount
+ run: echo "PR_COUNT=$(gh pr list --author ${{ steps.getMergedPullRequest.outputs.author }} --state any | grep -c '')" >> "$GITHUB_OUTPUT"
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+
+ - name: Comment on ${{ steps.getMergedPullRequest.outputs.author }}\'s first pull request!
+ if: ${{ fromJSON(steps.getPRCount.outputs.PR_COUNT) == 1 }}
+ run: |
+ gh pr comment ${{ steps.getMergedPullRequest.outputs.number }} --body \
+ "@${{ steps.getMergedPullRequest.outputs.author }}, Great job getting your first Expensify/App pull request over the finish line! :tada:
+
+ I know there's a lot of information in our [contributing guidelines](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md), so here are some points to take note of :memo::
+
+ 1. Now that your first PR has been merged, you can be hired for another issue. Once you've completed a few issues, you may be eligible to work on more than one job at a time.
+ 2. Once your PR is deployed to our staging servers, it will undergo quality assurance (QA) testing. If we find that it doesn't work as expected or causes a regression, you'll be responsible for fixing it. Typically, we would revert this PR and give you another chance to create a similar PR without causing a regression.
+ 3. Once your PR is deployed to _production_, we start a 7-day timer :alarm_clock:. After it has been on production for 7 days without causing any regressions, then we pay out the Upwork job. :moneybag:
+
+ So it might take a while before you're paid for your work, but we typically post multiple new jobs every day, so there's plenty of opportunity. I hope you've had a positive experience contributing to this repo! :blush:"
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
diff --git a/.imgbotconfig b/.imgbotconfig
new file mode 100644
index 000000000000..ff5c3345cc4d
--- /dev/null
+++ b/.imgbotconfig
@@ -0,0 +1,6 @@
+{
+ "ignoredFiles": [
+ "assets/images/empty-state_background-fade.png" // Caused an issue with colour gradients, https://github.com/Expensify/App/issues/30499
+ ],
+ "aggressiveCompression": "false"
+}
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/.prettierrc.js b/.prettierrc.js
index ad1fafbb51be..bcc67708cc95 100644
--- a/.prettierrc.js
+++ b/.prettierrc.js
@@ -6,4 +6,7 @@ module.exports = {
arrowParens: 'always',
printWidth: 190,
singleAttributePerLine: true,
+ importOrder: ['@assets/(.*)$', '@components/(.*)$', '@hooks/(.*)$', '@libs/(.*)$', '@navigation/(.*)$', '@pages/(.*)$', '@styles/(.*)$', '@userActions/(.*)$', '@src/(.*)$', '^[./]'],
+ importOrderSortSpecifiers: true,
+ importOrderCaseInsensitive: true,
};
diff --git a/.storybook/preview.js b/.storybook/preview.js
index a989960794f2..a89c720976c9 100644
--- a/.storybook/preview.js
+++ b/.storybook/preview.js
@@ -1,16 +1,16 @@
+import {PortalProvider} from '@gorhom/portal';
import React from 'react';
import Onyx from 'react-native-onyx';
import {SafeAreaProvider} from 'react-native-safe-area-context';
-import {PortalProvider} from '@gorhom/portal';
-import './fonts.css';
import ComposeProviders from '../src/components/ComposeProviders';
import HTMLEngineProvider from '../src/components/HTMLEngineProvider';
-import OnyxProvider from '../src/components/OnyxProvider';
import {LocaleContextProvider} from '../src/components/LocaleContextProvider';
-import {KeyboardStateProvider} from '../src/components/withKeyboardState';
+import OnyxProvider from '../src/components/OnyxProvider';
import {EnvironmentProvider} from '../src/components/withEnvironment';
+import {KeyboardStateProvider} from '../src/components/withKeyboardState';
import {WindowDimensionsProvider} from '../src/components/withWindowDimensions';
import ONYXKEYS from '../src/ONYXKEYS';
+import './fonts.css';
Onyx.init({
keys: ONYXKEYS,
diff --git a/.storybook/public/logo.png b/.storybook/public/logo.png
index 23c909e83f0b..5ba694bac764 100644
Binary files a/.storybook/public/logo.png and b/.storybook/public/logo.png differ
diff --git a/.storybook/public/logomark.svg b/.storybook/public/logomark.svg
index d1ca5ca84d06..ae263af72c12 100644
--- a/.storybook/public/logomark.svg
+++ b/.storybook/public/logomark.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js
index 3c5dbb41ea2c..fe58f3c0a6d8 100644
--- a/.storybook/webpack.config.js
+++ b/.storybook/webpack.config.js
@@ -28,6 +28,9 @@ module.exports = ({config}) => {
'react-native-web': '@expensify/react-native-web',
'@react-native-community/netinfo': path.resolve(__dirname, '../__mocks__/@react-native-community/netinfo.js'),
'@react-navigation/native': path.resolve(__dirname, '../__mocks__/@react-navigation/native'),
+
+ // Module alias support for storybook files, coping from `webpack.common.js`
+ ...custom.resolve.alias,
};
// Necessary to overwrite the values in the existing DefinePlugin hardcoded to the Config staging values
diff --git a/README.md b/README.md
index 9aad797ebb51..998f185939fa 100644
--- a/README.md
+++ b/README.md
@@ -59,8 +59,7 @@ For an M1 Mac, read this [SO](https://stackoverflow.com/questions/64901180/how-t
## Running the Android app 🤖
* Before installing Android dependencies, you need to obtain a token from Mapbox to download their SDKs. Please run `npm run configure-mapbox` and follow the instructions. If you already did this step for iOS, there is no need to repeat this step.
-* Go through the instructions on [this SO post](https://stackoverflow.com/c/expensify/questions/13283/13284#13284) to start running the app on android.
-* For more information, go through the official React-Native instructions on [this page](https://reactnative.dev/docs/environment-setup#development-os) for "React Native CLI Quickstart" > Mac OS > Android
+* Go through the official React-Native instructions on [this page](https://reactnative.dev/docs/environment-setup?guide=native&platform=android) to start running the app on android.
* If you are an Expensify employee and want to point the emulator to your local VM, follow [this](https://stackoverflow.com/c/expensify/questions/7699)
* To run a on a **Development Emulator**: `npm run android`
* Changes applied to Javascript will be applied automatically, any changes to native code will require a recompile
diff --git a/__mocks__/react-native-safe-area-context.js b/__mocks__/react-native-safe-area-context.js
index 4b4af7841c2c..b31ed670b81c 100644
--- a/__mocks__/react-native-safe-area-context.js
+++ b/__mocks__/react-native-safe-area-context.js
@@ -20,13 +20,18 @@ function withSafeAreaInsets(WrappedComponent) {
/>
);
}
- return forwardRef((props, ref) => (
+
+ const WithSafeAreaInsetsWithRef = forwardRef((props, ref) => (
));
+
+ WithSafeAreaInsetsWithRef.displayName = 'WithSafeAreaInsetsWithRef';
+
+ return WithSafeAreaInsetsWithRef;
}
const SafeAreaView = View;
diff --git a/android/app/build.gradle b/android/app/build.gradle
index b801bd34b244..badc6ed25b07 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -90,8 +90,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001039001
- versionName "1.3.90-1"
+ versionCode 1001039300
+ versionName "1.3.93-0"
}
flavorDimensions "default"
diff --git a/android/app/src/adhoc/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/adhoc/res/mipmap-hdpi/ic_launcher_foreground.png
index ecf9a8d7648a..f0cf22860e16 100644
Binary files a/android/app/src/adhoc/res/mipmap-hdpi/ic_launcher_foreground.png and b/android/app/src/adhoc/res/mipmap-hdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/adhoc/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/adhoc/res/mipmap-mdpi/ic_launcher_foreground.png
index ba8a2086138c..8070c42691fe 100644
Binary files a/android/app/src/adhoc/res/mipmap-mdpi/ic_launcher_foreground.png and b/android/app/src/adhoc/res/mipmap-mdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/adhoc/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/adhoc/res/mipmap-xhdpi/ic_launcher_foreground.png
index d1e6dbf34a18..06f3ee842084 100644
Binary files a/android/app/src/adhoc/res/mipmap-xhdpi/ic_launcher_foreground.png and b/android/app/src/adhoc/res/mipmap-xhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher.png
index fe443ce3f696..7a69e882941e 100644
Binary files a/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_foreground.png
index 2bb80c3d622b..692e5d1fac3f 100644
Binary files a/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_foreground.png and b/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_round.png
index fe443ce3f696..7a69e882941e 100644
Binary files a/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_round.png and b/android/app/src/adhoc/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher.png
index 576097130442..d7d01c5f0c0a 100644
Binary files a/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_foreground.png
index 576550530857..5b1e8667481b 100644
Binary files a/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_foreground.png and b/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ
diff --git a/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_round.png
index 576097130442..d7d01c5f0c0a 100644
Binary files a/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_round.png and b/android/app/src/adhoc/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/development/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/development/res/mipmap-xxhdpi/ic_launcher.png
index 474e8eca239a..a241d41d34fe 100644
Binary files a/android/app/src/development/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/development/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/development/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/development/res/mipmap-xxhdpi/ic_launcher_round.png
index 474e8eca239a..a241d41d34fe 100644
Binary files a/android/app/src/development/res/mipmap-xxhdpi/ic_launcher_round.png and b/android/app/src/development/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher.png
index 37c8716987f7..996266b64f6e 100644
Binary files a/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher_round.png
index 37c8716987f7..996266b64f6e 100644
Binary files a/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher_round.png and b/android/app/src/development/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification.png b/android/app/src/main/res/drawable-hdpi/ic_notification.png
index 7612112d1bc5..1d7e563f77ad 100644
Binary files a/android/app/src/main/res/drawable-hdpi/ic_notification.png and b/android/app/src/main/res/drawable-hdpi/ic_notification.png differ
diff --git a/android/app/src/main/res/drawable-xhdpi/ic_notification.png b/android/app/src/main/res/drawable-xhdpi/ic_notification.png
index a01f2c5e0dc9..e7fe54ede5d3 100644
Binary files a/android/app/src/main/res/drawable-xhdpi/ic_notification.png and b/android/app/src/main/res/drawable-xhdpi/ic_notification.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png b/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png
index 06b2bfc8447b..f123d07f59c2 100644
Binary files a/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png and b/android/app/src/main/res/drawable-xxhdpi/bootsplash_logo.png differ
diff --git a/android/app/src/main/res/drawable-xxhdpi/ic_notification.png b/android/app/src/main/res/drawable-xxhdpi/ic_notification.png
index 3bb969329c79..c27e58558a92 100644
Binary files a/android/app/src/main/res/drawable-xxhdpi/ic_notification.png and b/android/app/src/main/res/drawable-xxhdpi/ic_notification.png differ
diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png
index 697922b1e689..da1caf86e66f 100644
Binary files a/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png and b/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 630ffa310345..f533b4e8d230 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index 630ffa310345..f533b4e8d230 100644
Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index d157a530d098..ee08d91ae4a7 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index d157a530d098..ee08d91ae4a7 100644
Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/assets/emojis/common.js b/assets/emojis/common.js
index e8a8b15c2dd5..b7593b6e2960 100644
--- a/assets/emojis/common.js
+++ b/assets/emojis/common.js
@@ -1,11 +1,11 @@
import Smiley from '../images/emoji.svg';
-import AnimalsAndNature from '../images/emojiCategoryIcons/plant.svg';
+import Flags from '../images/emojiCategoryIcons/flag.svg';
import FoodAndDrink from '../images/emojiCategoryIcons/hamburger.svg';
-import TravelAndPlaces from '../images/emojiCategoryIcons/plane.svg';
-import Activities from '../images/emojiCategoryIcons/soccer-ball.svg';
import Objects from '../images/emojiCategoryIcons/light-bulb.svg';
import Symbols from '../images/emojiCategoryIcons/peace-sign.svg';
-import Flags from '../images/emojiCategoryIcons/flag.svg';
+import TravelAndPlaces from '../images/emojiCategoryIcons/plane.svg';
+import AnimalsAndNature from '../images/emojiCategoryIcons/plant.svg';
+import Activities from '../images/emojiCategoryIcons/soccer-ball.svg';
import FrequentlyUsed from '../images/history.svg';
const skinTones = [
diff --git a/assets/images/MCCGroupIcons/MCC-Airlines.svg b/assets/images/MCCGroupIcons/MCC-Airlines.svg
index b707faf9857e..a316bfbc0a8a 100644
--- a/assets/images/MCCGroupIcons/MCC-Airlines.svg
+++ b/assets/images/MCCGroupIcons/MCC-Airlines.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Commuter.svg b/assets/images/MCCGroupIcons/MCC-Commuter.svg
index d8f808cf463b..88ad3085b37a 100644
--- a/assets/images/MCCGroupIcons/MCC-Commuter.svg
+++ b/assets/images/MCCGroupIcons/MCC-Commuter.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Gas.svg b/assets/images/MCCGroupIcons/MCC-Gas.svg
index b13e657a1af4..efc417df2133 100644
--- a/assets/images/MCCGroupIcons/MCC-Gas.svg
+++ b/assets/images/MCCGroupIcons/MCC-Gas.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Goods.svg b/assets/images/MCCGroupIcons/MCC-Goods.svg
index e3ea39f77344..fe137a8fae18 100644
--- a/assets/images/MCCGroupIcons/MCC-Goods.svg
+++ b/assets/images/MCCGroupIcons/MCC-Goods.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Groceries.svg b/assets/images/MCCGroupIcons/MCC-Groceries.svg
index 349154ca5496..0b766abe1ef8 100644
--- a/assets/images/MCCGroupIcons/MCC-Groceries.svg
+++ b/assets/images/MCCGroupIcons/MCC-Groceries.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Hotel.svg b/assets/images/MCCGroupIcons/MCC-Hotel.svg
index 04be004b24bb..94f97659fd5d 100644
--- a/assets/images/MCCGroupIcons/MCC-Hotel.svg
+++ b/assets/images/MCCGroupIcons/MCC-Hotel.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Mail.svg b/assets/images/MCCGroupIcons/MCC-Mail.svg
index e554fa44f37f..96dff88527e0 100644
--- a/assets/images/MCCGroupIcons/MCC-Mail.svg
+++ b/assets/images/MCCGroupIcons/MCC-Mail.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Meals.svg b/assets/images/MCCGroupIcons/MCC-Meals.svg
index df3672cf52a6..6cc1ac414062 100644
--- a/assets/images/MCCGroupIcons/MCC-Meals.svg
+++ b/assets/images/MCCGroupIcons/MCC-Meals.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Misc.svg b/assets/images/MCCGroupIcons/MCC-Misc.svg
index a4ef1615d146..d8fd071043e5 100644
--- a/assets/images/MCCGroupIcons/MCC-Misc.svg
+++ b/assets/images/MCCGroupIcons/MCC-Misc.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-RentalCar.svg b/assets/images/MCCGroupIcons/MCC-RentalCar.svg
index 789cb5bc3fe3..e8dd3f59954c 100644
--- a/assets/images/MCCGroupIcons/MCC-RentalCar.svg
+++ b/assets/images/MCCGroupIcons/MCC-RentalCar.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Services.svg b/assets/images/MCCGroupIcons/MCC-Services.svg
index 25c67065c105..265491c36eff 100644
--- a/assets/images/MCCGroupIcons/MCC-Services.svg
+++ b/assets/images/MCCGroupIcons/MCC-Services.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Taxi.svg b/assets/images/MCCGroupIcons/MCC-Taxi.svg
index 2cc31e4db079..6eb88b43c725 100644
--- a/assets/images/MCCGroupIcons/MCC-Taxi.svg
+++ b/assets/images/MCCGroupIcons/MCC-Taxi.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/MCCGroupIcons/MCC-Utilities.svg b/assets/images/MCCGroupIcons/MCC-Utilities.svg
index 27e7290bf4e5..36b7fb392d79 100644
--- a/assets/images/MCCGroupIcons/MCC-Utilities.svg
+++ b/assets/images/MCCGroupIcons/MCC-Utilities.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/add-reaction.svg b/assets/images/add-reaction.svg
index a576e2c84622..d70d0acec190 100644
--- a/assets/images/add-reaction.svg
+++ b/assets/images/add-reaction.svg
@@ -1,5 +1 @@
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/assets/images/android.svg b/assets/images/android.svg
index 0ee0daa9cc37..2599b0aed9fa 100644
--- a/assets/images/android.svg
+++ b/assets/images/android.svg
@@ -1,22 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/apple.svg b/assets/images/apple.svg
index 44e7f309f7ce..69e8d3b535c1 100644
--- a/assets/images/apple.svg
+++ b/assets/images/apple.svg
@@ -1,21 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/arrow-right-long.svg b/assets/images/arrow-right-long.svg
index 99be81fa9b36..6ab65ef779b8 100644
--- a/assets/images/arrow-right-long.svg
+++ b/assets/images/arrow-right-long.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/arrow-right.svg b/assets/images/arrow-right.svg
index c3bb5345d3f9..df13c75ca414 100644
--- a/assets/images/arrow-right.svg
+++ b/assets/images/arrow-right.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/arrow-up.svg b/assets/images/arrow-up.svg
index 60d03289d446..9183b18402d0 100644
--- a/assets/images/arrow-up.svg
+++ b/assets/images/arrow-up.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/arrows-updown.svg b/assets/images/arrows-updown.svg
index a1aa2c92ef87..2c8d2f788d33 100644
--- a/assets/images/arrows-updown.svg
+++ b/assets/images/arrows-updown.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/admin-room.svg b/assets/images/avatars/admin-room.svg
index aa25fe5bbb1d..486137d825dc 100644
--- a/assets/images/avatars/admin-room.svg
+++ b/assets/images/avatars/admin-room.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/announce-room.svg b/assets/images/avatars/announce-room.svg
index 772a113fbc33..538d78d6a8f6 100644
--- a/assets/images/avatars/announce-room.svg
+++ b/assets/images/avatars/announce-room.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/concierge-avatar.svg b/assets/images/avatars/concierge-avatar.svg
index d2a7cf31ac98..eb374a9a5a68 100644
--- a/assets/images/avatars/concierge-avatar.svg
+++ b/assets/images/avatars/concierge-avatar.svg
@@ -1,39 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/deleted-room.svg b/assets/images/avatars/deleted-room.svg
index a39c55d0e2b5..dafcb9d95a84 100644
--- a/assets/images/avatars/deleted-room.svg
+++ b/assets/images/avatars/deleted-room.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/domain-room.svg b/assets/images/avatars/domain-room.svg
index 1f9903539049..66d1d5ab96fc 100644
--- a/assets/images/avatars/domain-room.svg
+++ b/assets/images/avatars/domain-room.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/fallback-avatar.svg b/assets/images/avatars/fallback-avatar.svg
index 0d71e0fbc210..b4584d910190 100644
--- a/assets/images/avatars/fallback-avatar.svg
+++ b/assets/images/avatars/fallback-avatar.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/fallback-workspace-avatar.svg b/assets/images/avatars/fallback-workspace-avatar.svg
index 518627fafc19..74edba02f4b5 100644
--- a/assets/images/avatars/fallback-workspace-avatar.svg
+++ b/assets/images/avatars/fallback-workspace-avatar.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/room.png b/assets/images/avatars/room.png
index dca457fbfdf7..ef5073a9a6e1 100644
Binary files a/assets/images/avatars/room.png and b/assets/images/avatars/room.png differ
diff --git a/assets/images/avatars/room.svg b/assets/images/avatars/room.svg
index 0db866ad9160..f3b59a00bfbd 100644
--- a/assets/images/avatars/room.svg
+++ b/assets/images/avatars/room.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_1.svg b/assets/images/avatars/user/default-avatar_1.svg
index dd4d59b26158..971389c480cf 100644
--- a/assets/images/avatars/user/default-avatar_1.svg
+++ b/assets/images/avatars/user/default-avatar_1.svg
@@ -1,168 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_10.svg b/assets/images/avatars/user/default-avatar_10.svg
index 85979a5d1414..0f0484833f4b 100644
--- a/assets/images/avatars/user/default-avatar_10.svg
+++ b/assets/images/avatars/user/default-avatar_10.svg
@@ -1,192 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_11.svg b/assets/images/avatars/user/default-avatar_11.svg
index eb1ce99f43c9..1e1b3ca44e82 100644
--- a/assets/images/avatars/user/default-avatar_11.svg
+++ b/assets/images/avatars/user/default-avatar_11.svg
@@ -1,156 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_12.svg b/assets/images/avatars/user/default-avatar_12.svg
index fd5635c4e9c4..b066595be3ea 100644
--- a/assets/images/avatars/user/default-avatar_12.svg
+++ b/assets/images/avatars/user/default-avatar_12.svg
@@ -1,163 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_13.svg b/assets/images/avatars/user/default-avatar_13.svg
index b6850c8585ca..5e9779467fe0 100644
--- a/assets/images/avatars/user/default-avatar_13.svg
+++ b/assets/images/avatars/user/default-avatar_13.svg
@@ -1,229 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_14.svg b/assets/images/avatars/user/default-avatar_14.svg
index f888b5960b09..aa8d3b39327e 100644
--- a/assets/images/avatars/user/default-avatar_14.svg
+++ b/assets/images/avatars/user/default-avatar_14.svg
@@ -1,210 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_15.svg b/assets/images/avatars/user/default-avatar_15.svg
index 4a20f351c0dc..1748cda659ae 100644
--- a/assets/images/avatars/user/default-avatar_15.svg
+++ b/assets/images/avatars/user/default-avatar_15.svg
@@ -1,173 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_16.svg b/assets/images/avatars/user/default-avatar_16.svg
index a8edcb5540e1..8ca55805cec6 100644
--- a/assets/images/avatars/user/default-avatar_16.svg
+++ b/assets/images/avatars/user/default-avatar_16.svg
@@ -1,269 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_17.svg b/assets/images/avatars/user/default-avatar_17.svg
index b1fffeb4f508..1ce8f204c2ab 100644
--- a/assets/images/avatars/user/default-avatar_17.svg
+++ b/assets/images/avatars/user/default-avatar_17.svg
@@ -1,164 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_18.svg b/assets/images/avatars/user/default-avatar_18.svg
index d1a6c8dd2ddc..770095ecc654 100644
--- a/assets/images/avatars/user/default-avatar_18.svg
+++ b/assets/images/avatars/user/default-avatar_18.svg
@@ -1,155 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_19.svg b/assets/images/avatars/user/default-avatar_19.svg
index 10d1a864088c..9049a504514c 100644
--- a/assets/images/avatars/user/default-avatar_19.svg
+++ b/assets/images/avatars/user/default-avatar_19.svg
@@ -1,171 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_2.svg b/assets/images/avatars/user/default-avatar_2.svg
index 9b2b7a72f37a..dacfc5467b59 100644
--- a/assets/images/avatars/user/default-avatar_2.svg
+++ b/assets/images/avatars/user/default-avatar_2.svg
@@ -1,124 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_20.svg b/assets/images/avatars/user/default-avatar_20.svg
index 6b5751726843..b0adfa9fc311 100644
--- a/assets/images/avatars/user/default-avatar_20.svg
+++ b/assets/images/avatars/user/default-avatar_20.svg
@@ -1,179 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_21.svg b/assets/images/avatars/user/default-avatar_21.svg
index 6afea275de75..4764672b9e0c 100644
--- a/assets/images/avatars/user/default-avatar_21.svg
+++ b/assets/images/avatars/user/default-avatar_21.svg
@@ -1,163 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_22.svg b/assets/images/avatars/user/default-avatar_22.svg
index da9ab029d62b..428ae4207f76 100644
--- a/assets/images/avatars/user/default-avatar_22.svg
+++ b/assets/images/avatars/user/default-avatar_22.svg
@@ -1,206 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_23.svg b/assets/images/avatars/user/default-avatar_23.svg
index f2afe88238a7..5bef9f1c2221 100644
--- a/assets/images/avatars/user/default-avatar_23.svg
+++ b/assets/images/avatars/user/default-avatar_23.svg
@@ -1,196 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_24.svg b/assets/images/avatars/user/default-avatar_24.svg
index 1ea472d24d83..4400546c356f 100644
--- a/assets/images/avatars/user/default-avatar_24.svg
+++ b/assets/images/avatars/user/default-avatar_24.svg
@@ -1,241 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_3.svg b/assets/images/avatars/user/default-avatar_3.svg
index 6ddd44d51cb2..11657fcbb2b1 100644
--- a/assets/images/avatars/user/default-avatar_3.svg
+++ b/assets/images/avatars/user/default-avatar_3.svg
@@ -1,230 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_4.svg b/assets/images/avatars/user/default-avatar_4.svg
index 203c2f990d28..cda04362b4e5 100644
--- a/assets/images/avatars/user/default-avatar_4.svg
+++ b/assets/images/avatars/user/default-avatar_4.svg
@@ -1,216 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_5.svg b/assets/images/avatars/user/default-avatar_5.svg
index 7be508c86c6d..17b662838d43 100644
--- a/assets/images/avatars/user/default-avatar_5.svg
+++ b/assets/images/avatars/user/default-avatar_5.svg
@@ -1,185 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_6.svg b/assets/images/avatars/user/default-avatar_6.svg
index 67774100ca12..8f5575557154 100644
--- a/assets/images/avatars/user/default-avatar_6.svg
+++ b/assets/images/avatars/user/default-avatar_6.svg
@@ -1,193 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_7.svg b/assets/images/avatars/user/default-avatar_7.svg
index b1aad6c7c3f1..1136f086ade0 100644
--- a/assets/images/avatars/user/default-avatar_7.svg
+++ b/assets/images/avatars/user/default-avatar_7.svg
@@ -1,215 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_8.svg b/assets/images/avatars/user/default-avatar_8.svg
index 55a4828cc824..f0e7d8f288e6 100644
--- a/assets/images/avatars/user/default-avatar_8.svg
+++ b/assets/images/avatars/user/default-avatar_8.svg
@@ -1,184 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/user/default-avatar_9.svg b/assets/images/avatars/user/default-avatar_9.svg
index 1c65c8cc2916..4bbb156b7899 100644
--- a/assets/images/avatars/user/default-avatar_9.svg
+++ b/assets/images/avatars/user/default-avatar_9.svg
@@ -1,117 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_0.svg b/assets/images/avatars/workspace/default-avatar_0.svg
index c942281517f4..8ebc0bbe6001 100644
--- a/assets/images/avatars/workspace/default-avatar_0.svg
+++ b/assets/images/avatars/workspace/default-avatar_0.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_1.svg b/assets/images/avatars/workspace/default-avatar_1.svg
index e6b0c71b53d4..ba5e41639b4f 100644
--- a/assets/images/avatars/workspace/default-avatar_1.svg
+++ b/assets/images/avatars/workspace/default-avatar_1.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_2.svg b/assets/images/avatars/workspace/default-avatar_2.svg
index c7d469d662ba..4257049a1146 100644
--- a/assets/images/avatars/workspace/default-avatar_2.svg
+++ b/assets/images/avatars/workspace/default-avatar_2.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_3.svg b/assets/images/avatars/workspace/default-avatar_3.svg
index 04c5d6d99372..ce049452aa83 100644
--- a/assets/images/avatars/workspace/default-avatar_3.svg
+++ b/assets/images/avatars/workspace/default-avatar_3.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_4.svg b/assets/images/avatars/workspace/default-avatar_4.svg
index e547481faefd..28c5b936cf1a 100644
--- a/assets/images/avatars/workspace/default-avatar_4.svg
+++ b/assets/images/avatars/workspace/default-avatar_4.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_5.svg b/assets/images/avatars/workspace/default-avatar_5.svg
index 6b8c654ee784..3821dd80bd89 100644
--- a/assets/images/avatars/workspace/default-avatar_5.svg
+++ b/assets/images/avatars/workspace/default-avatar_5.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_6.svg b/assets/images/avatars/workspace/default-avatar_6.svg
index c8f155995263..0eebd4c55280 100644
--- a/assets/images/avatars/workspace/default-avatar_6.svg
+++ b/assets/images/avatars/workspace/default-avatar_6.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_7.svg b/assets/images/avatars/workspace/default-avatar_7.svg
index 714725c62f2f..5563ae3941cc 100644
--- a/assets/images/avatars/workspace/default-avatar_7.svg
+++ b/assets/images/avatars/workspace/default-avatar_7.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_8.svg b/assets/images/avatars/workspace/default-avatar_8.svg
index edca9a464610..5cb8e1b6a500 100644
--- a/assets/images/avatars/workspace/default-avatar_8.svg
+++ b/assets/images/avatars/workspace/default-avatar_8.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_9.svg b/assets/images/avatars/workspace/default-avatar_9.svg
index 0cc78a5dae7e..a15970c7f27d 100644
--- a/assets/images/avatars/workspace/default-avatar_9.svg
+++ b/assets/images/avatars/workspace/default-avatar_9.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_a.svg b/assets/images/avatars/workspace/default-avatar_a.svg
index 5ea6d7a1dd0e..c29a681165d1 100644
--- a/assets/images/avatars/workspace/default-avatar_a.svg
+++ b/assets/images/avatars/workspace/default-avatar_a.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_b.svg b/assets/images/avatars/workspace/default-avatar_b.svg
index dfdef9451455..e376df224c1a 100644
--- a/assets/images/avatars/workspace/default-avatar_b.svg
+++ b/assets/images/avatars/workspace/default-avatar_b.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_building.svg b/assets/images/avatars/workspace/default-avatar_building.svg
index 69c0f0e73dc4..6175ce27d1af 100644
--- a/assets/images/avatars/workspace/default-avatar_building.svg
+++ b/assets/images/avatars/workspace/default-avatar_building.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_c.svg b/assets/images/avatars/workspace/default-avatar_c.svg
index d09cd384d458..cd8f585e4ce3 100644
--- a/assets/images/avatars/workspace/default-avatar_c.svg
+++ b/assets/images/avatars/workspace/default-avatar_c.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_d.svg b/assets/images/avatars/workspace/default-avatar_d.svg
index 2d8fb68adf58..98a87ceb2a59 100644
--- a/assets/images/avatars/workspace/default-avatar_d.svg
+++ b/assets/images/avatars/workspace/default-avatar_d.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_e.svg b/assets/images/avatars/workspace/default-avatar_e.svg
index a21981f244c5..1b8453ad6063 100644
--- a/assets/images/avatars/workspace/default-avatar_e.svg
+++ b/assets/images/avatars/workspace/default-avatar_e.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_f.svg b/assets/images/avatars/workspace/default-avatar_f.svg
index 2f1323e2c7f9..9bf793bf49dd 100644
--- a/assets/images/avatars/workspace/default-avatar_f.svg
+++ b/assets/images/avatars/workspace/default-avatar_f.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_g.svg b/assets/images/avatars/workspace/default-avatar_g.svg
index 51ff96cdfb7b..fd9212faef4e 100644
--- a/assets/images/avatars/workspace/default-avatar_g.svg
+++ b/assets/images/avatars/workspace/default-avatar_g.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_h.svg b/assets/images/avatars/workspace/default-avatar_h.svg
index ddabaa42d06b..3fd678ddb2f9 100644
--- a/assets/images/avatars/workspace/default-avatar_h.svg
+++ b/assets/images/avatars/workspace/default-avatar_h.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_i.svg b/assets/images/avatars/workspace/default-avatar_i.svg
index e9bc60254e2e..f565ea0bd01d 100644
--- a/assets/images/avatars/workspace/default-avatar_i.svg
+++ b/assets/images/avatars/workspace/default-avatar_i.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_j.svg b/assets/images/avatars/workspace/default-avatar_j.svg
index 9daf382ca8ef..35f709340cc0 100644
--- a/assets/images/avatars/workspace/default-avatar_j.svg
+++ b/assets/images/avatars/workspace/default-avatar_j.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_k.svg b/assets/images/avatars/workspace/default-avatar_k.svg
index 6018a9912f2c..b9b15c6b1b7e 100644
--- a/assets/images/avatars/workspace/default-avatar_k.svg
+++ b/assets/images/avatars/workspace/default-avatar_k.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_l.svg b/assets/images/avatars/workspace/default-avatar_l.svg
index 4fd4e62ff93a..3cd5b6ef2b19 100644
--- a/assets/images/avatars/workspace/default-avatar_l.svg
+++ b/assets/images/avatars/workspace/default-avatar_l.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_m.svg b/assets/images/avatars/workspace/default-avatar_m.svg
index e2eea24f1af9..389f8dd12f89 100644
--- a/assets/images/avatars/workspace/default-avatar_m.svg
+++ b/assets/images/avatars/workspace/default-avatar_m.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_n.svg b/assets/images/avatars/workspace/default-avatar_n.svg
index d1f036614c08..6abbde1c8b2b 100644
--- a/assets/images/avatars/workspace/default-avatar_n.svg
+++ b/assets/images/avatars/workspace/default-avatar_n.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_o.svg b/assets/images/avatars/workspace/default-avatar_o.svg
index 5f2c8e89fc89..2257cb9cd3ce 100644
--- a/assets/images/avatars/workspace/default-avatar_o.svg
+++ b/assets/images/avatars/workspace/default-avatar_o.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_p.svg b/assets/images/avatars/workspace/default-avatar_p.svg
index 4729bbc0afb9..4d09abfb08a1 100644
--- a/assets/images/avatars/workspace/default-avatar_p.svg
+++ b/assets/images/avatars/workspace/default-avatar_p.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_q.svg b/assets/images/avatars/workspace/default-avatar_q.svg
index ebdd318460e9..267e8a431346 100644
--- a/assets/images/avatars/workspace/default-avatar_q.svg
+++ b/assets/images/avatars/workspace/default-avatar_q.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_r.svg b/assets/images/avatars/workspace/default-avatar_r.svg
index 015869a190ad..76fb0e3dbebd 100644
--- a/assets/images/avatars/workspace/default-avatar_r.svg
+++ b/assets/images/avatars/workspace/default-avatar_r.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_s.svg b/assets/images/avatars/workspace/default-avatar_s.svg
index 334af3a15636..1fe3d7dd20f8 100644
--- a/assets/images/avatars/workspace/default-avatar_s.svg
+++ b/assets/images/avatars/workspace/default-avatar_s.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_t.svg b/assets/images/avatars/workspace/default-avatar_t.svg
index 9ab5962f9ba1..e4aad4cbdd4e 100644
--- a/assets/images/avatars/workspace/default-avatar_t.svg
+++ b/assets/images/avatars/workspace/default-avatar_t.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_u.svg b/assets/images/avatars/workspace/default-avatar_u.svg
index 04daa1bd4b04..b7cc5a0d50be 100644
--- a/assets/images/avatars/workspace/default-avatar_u.svg
+++ b/assets/images/avatars/workspace/default-avatar_u.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_v.svg b/assets/images/avatars/workspace/default-avatar_v.svg
index a94242b787e0..fdb2d5e3030f 100644
--- a/assets/images/avatars/workspace/default-avatar_v.svg
+++ b/assets/images/avatars/workspace/default-avatar_v.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_w.svg b/assets/images/avatars/workspace/default-avatar_w.svg
index a0756f443422..a8a04f28f976 100644
--- a/assets/images/avatars/workspace/default-avatar_w.svg
+++ b/assets/images/avatars/workspace/default-avatar_w.svg
@@ -1,20 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_x.svg b/assets/images/avatars/workspace/default-avatar_x.svg
index 516da8c1b563..16a125595699 100644
--- a/assets/images/avatars/workspace/default-avatar_x.svg
+++ b/assets/images/avatars/workspace/default-avatar_x.svg
@@ -1,20 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_y.svg b/assets/images/avatars/workspace/default-avatar_y.svg
index 435d0d79bc79..7bb286561588 100644
--- a/assets/images/avatars/workspace/default-avatar_y.svg
+++ b/assets/images/avatars/workspace/default-avatar_y.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/avatars/workspace/default-avatar_z.svg b/assets/images/avatars/workspace/default-avatar_z.svg
index 48bb76f4a72a..5966eb43c74b 100644
--- a/assets/images/avatars/workspace/default-avatar_z.svg
+++ b/assets/images/avatars/workspace/default-avatar_z.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/back-left.svg b/assets/images/back-left.svg
index c6730b492228..51164100ff59 100644
--- a/assets/images/back-left.svg
+++ b/assets/images/back-left.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bank.svg b/assets/images/bank.svg
index 87a75b644a3a..c23f578a708a 100644
--- a/assets/images/bank.svg
+++ b/assets/images/bank.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/american-express.svg b/assets/images/bankicons/american-express.svg
index 0ab8383d46ed..57696764f6cf 100644
--- a/assets/images/bankicons/american-express.svg
+++ b/assets/images/bankicons/american-express.svg
@@ -1,23 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/bank-of-america.svg b/assets/images/bankicons/bank-of-america.svg
index e4f87be611fc..7a8d43c545a1 100644
--- a/assets/images/bankicons/bank-of-america.svg
+++ b/assets/images/bankicons/bank-of-america.svg
@@ -1,22 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/bb-t.svg b/assets/images/bankicons/bb-t.svg
index 7e7bf1f29ee4..af36426d11f3 100644
--- a/assets/images/bankicons/bb-t.svg
+++ b/assets/images/bankicons/bb-t.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/capital-one.svg b/assets/images/bankicons/capital-one.svg
index c37c8e3ca582..be25c3120d2d 100644
--- a/assets/images/bankicons/capital-one.svg
+++ b/assets/images/bankicons/capital-one.svg
@@ -1,53 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/charles-schwab.svg b/assets/images/bankicons/charles-schwab.svg
index 181a668965da..369f17822511 100644
--- a/assets/images/bankicons/charles-schwab.svg
+++ b/assets/images/bankicons/charles-schwab.svg
@@ -1,58 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/chase.svg b/assets/images/bankicons/chase.svg
index 70f0b911f147..2b73256b6427 100644
--- a/assets/images/bankicons/chase.svg
+++ b/assets/images/bankicons/chase.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/citibank.svg b/assets/images/bankicons/citibank.svg
index b03e1efe9bb6..e0bc5d44d9ba 100644
--- a/assets/images/bankicons/citibank.svg
+++ b/assets/images/bankicons/citibank.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/citizens-bank.svg b/assets/images/bankicons/citizens-bank.svg
index a0cdc6c1df2b..76f650f59629 100644
--- a/assets/images/bankicons/citizens-bank.svg
+++ b/assets/images/bankicons/citizens-bank.svg
@@ -1,47 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/discover.svg b/assets/images/bankicons/discover.svg
index 75db16e4d1c1..52ead095ed48 100644
--- a/assets/images/bankicons/discover.svg
+++ b/assets/images/bankicons/discover.svg
@@ -1,47 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/expensify-background.png b/assets/images/bankicons/expensify-background.png
index ab7b71d34e11..c06ff4c2725f 100644
Binary files a/assets/images/bankicons/expensify-background.png and b/assets/images/bankicons/expensify-background.png differ
diff --git a/assets/images/bankicons/expensify.svg b/assets/images/bankicons/expensify.svg
index b61773e8d838..95c07b9de619 100644
--- a/assets/images/bankicons/expensify.svg
+++ b/assets/images/bankicons/expensify.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/fidelity.svg b/assets/images/bankicons/fidelity.svg
index d49eca17c12d..bd865f145200 100644
--- a/assets/images/bankicons/fidelity.svg
+++ b/assets/images/bankicons/fidelity.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/generic-bank-account.svg b/assets/images/bankicons/generic-bank-account.svg
index 493f06b335d8..52ed3f7a1dea 100644
--- a/assets/images/bankicons/generic-bank-account.svg
+++ b/assets/images/bankicons/generic-bank-account.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/huntington-bank.svg b/assets/images/bankicons/huntington-bank.svg
index 40909a273e19..de38785b6c4e 100644
--- a/assets/images/bankicons/huntington-bank.svg
+++ b/assets/images/bankicons/huntington-bank.svg
@@ -1,22 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/navy-federal-credit-union.svg b/assets/images/bankicons/navy-federal-credit-union.svg
index 898cd03768f0..4f57cedc5a6e 100644
--- a/assets/images/bankicons/navy-federal-credit-union.svg
+++ b/assets/images/bankicons/navy-federal-credit-union.svg
@@ -1,85 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/pnc.svg b/assets/images/bankicons/pnc.svg
index 3f78dbe94f47..bf4301979bba 100644
--- a/assets/images/bankicons/pnc.svg
+++ b/assets/images/bankicons/pnc.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/regions-bank.svg b/assets/images/bankicons/regions-bank.svg
index bff045f0eb5a..f3d970e3a8a8 100644
--- a/assets/images/bankicons/regions-bank.svg
+++ b/assets/images/bankicons/regions-bank.svg
@@ -1,38 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/suntrust.svg b/assets/images/bankicons/suntrust.svg
index b5b94c105b14..184d04f1e5dd 100644
--- a/assets/images/bankicons/suntrust.svg
+++ b/assets/images/bankicons/suntrust.svg
@@ -1,217 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/td-bank.svg b/assets/images/bankicons/td-bank.svg
index 84675de5f2bf..63dba67711a7 100644
--- a/assets/images/bankicons/td-bank.svg
+++ b/assets/images/bankicons/td-bank.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/us-bank.svg b/assets/images/bankicons/us-bank.svg
index e091ba0a6f50..cf212c8f6464 100644
--- a/assets/images/bankicons/us-bank.svg
+++ b/assets/images/bankicons/us-bank.svg
@@ -1,27 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bankicons/usaa.svg b/assets/images/bankicons/usaa.svg
index 1e137fab626f..547209084ef4 100644
--- a/assets/images/bankicons/usaa.svg
+++ b/assets/images/bankicons/usaa.svg
@@ -1,36 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bell.svg b/assets/images/bell.svg
new file mode 100644
index 000000000000..6ba600dc695b
--- /dev/null
+++ b/assets/images/bell.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/assets/images/bellSlash.svg b/assets/images/bellSlash.svg
new file mode 100644
index 000000000000..488acc4de05e
--- /dev/null
+++ b/assets/images/bellSlash.svg
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/assets/images/bill.svg b/assets/images/bill.svg
index 6d9e7bd74ee6..c60dbfcc2bfe 100644
--- a/assets/images/bill.svg
+++ b/assets/images/bill.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bolt.svg b/assets/images/bolt.svg
index c54c044a898e..c8ea05c0b447 100644
--- a/assets/images/bolt.svg
+++ b/assets/images/bolt.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/briefcase.svg b/assets/images/briefcase.svg
index c73734c6b124..eb35954cbb15 100644
--- a/assets/images/briefcase.svg
+++ b/assets/images/briefcase.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/bug.svg b/assets/images/bug.svg
index 8a33c1c17437..ca405caea9ac 100644
--- a/assets/images/bug.svg
+++ b/assets/images/bug.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/building.svg b/assets/images/building.svg
index 27efe759f4e4..0254da81f38f 100644
--- a/assets/images/building.svg
+++ b/assets/images/building.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/calendar.svg b/assets/images/calendar.svg
index 18885029a7c8..f855bbad61eb 100644
--- a/assets/images/calendar.svg
+++ b/assets/images/calendar.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/camera.svg b/assets/images/camera.svg
index 966a185ae5d9..b40af157c275 100644
--- a/assets/images/camera.svg
+++ b/assets/images/camera.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/car.svg b/assets/images/car.svg
index 7172eb1db01e..6c765f34c2da 100644
--- a/assets/images/car.svg
+++ b/assets/images/car.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/american-express.svg b/assets/images/cardicons/american-express.svg
index 9e31f7c8a08e..201cc9262394 100644
--- a/assets/images/cardicons/american-express.svg
+++ b/assets/images/cardicons/american-express.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/bank-of-america.svg b/assets/images/cardicons/bank-of-america.svg
index 62dd510b0649..20f180ebfdd6 100644
--- a/assets/images/cardicons/bank-of-america.svg
+++ b/assets/images/cardicons/bank-of-america.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/bb-t.svg b/assets/images/cardicons/bb-t.svg
index ad3676458d21..f37d1fda7f8d 100644
--- a/assets/images/cardicons/bb-t.svg
+++ b/assets/images/cardicons/bb-t.svg
@@ -1,33 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/capital-one.svg b/assets/images/cardicons/capital-one.svg
index ee4f756e2600..6ac463b4193e 100644
--- a/assets/images/cardicons/capital-one.svg
+++ b/assets/images/cardicons/capital-one.svg
@@ -1,67 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/charles-schwab.svg b/assets/images/cardicons/charles-schwab.svg
index 39c894042cd3..b38ac495d779 100644
--- a/assets/images/cardicons/charles-schwab.svg
+++ b/assets/images/cardicons/charles-schwab.svg
@@ -1,76 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/chase.svg b/assets/images/cardicons/chase.svg
index 8e8ddb6d5378..7f0b8dfe62c2 100644
--- a/assets/images/cardicons/chase.svg
+++ b/assets/images/cardicons/chase.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/citibank.svg b/assets/images/cardicons/citibank.svg
index f9869aee7146..5bf890363378 100644
--- a/assets/images/cardicons/citibank.svg
+++ b/assets/images/cardicons/citibank.svg
@@ -1,22 +1 @@
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/citizens.svg b/assets/images/cardicons/citizens.svg
index 3b4bf9ea1af3..ec758b3c0935 100644
--- a/assets/images/cardicons/citizens.svg
+++ b/assets/images/cardicons/citizens.svg
@@ -1,57 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/discover.svg b/assets/images/cardicons/discover.svg
index 668e5634339d..a035727d3578 100644
--- a/assets/images/cardicons/discover.svg
+++ b/assets/images/cardicons/discover.svg
@@ -1,53 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/expensify-card-dark.svg b/assets/images/cardicons/expensify-card-dark.svg
index 4a65afeeda9d..7591a8abc29a 100644
--- a/assets/images/cardicons/expensify-card-dark.svg
+++ b/assets/images/cardicons/expensify-card-dark.svg
@@ -1,78 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/fidelity.svg b/assets/images/cardicons/fidelity.svg
index c87f9c4aa56c..385370d00060 100644
--- a/assets/images/cardicons/fidelity.svg
+++ b/assets/images/cardicons/fidelity.svg
@@ -1,21 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/generic-bank-card.svg b/assets/images/cardicons/generic-bank-card.svg
index f700691ac29b..6facb98577cb 100644
--- a/assets/images/cardicons/generic-bank-card.svg
+++ b/assets/images/cardicons/generic-bank-card.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/huntington-bank.svg b/assets/images/cardicons/huntington-bank.svg
index c108c7039898..6a1d50d998a6 100644
--- a/assets/images/cardicons/huntington-bank.svg
+++ b/assets/images/cardicons/huntington-bank.svg
@@ -1,26 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/navy-federal-credit-union.svg b/assets/images/cardicons/navy-federal-credit-union.svg
index 5abc1103cce1..b67aec1a1a5f 100644
--- a/assets/images/cardicons/navy-federal-credit-union.svg
+++ b/assets/images/cardicons/navy-federal-credit-union.svg
@@ -1,105 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/pnc.svg b/assets/images/cardicons/pnc.svg
index ae4d4aac8e41..839e630a1b85 100644
--- a/assets/images/cardicons/pnc.svg
+++ b/assets/images/cardicons/pnc.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/regions-bank.svg b/assets/images/cardicons/regions-bank.svg
index 1837ad2be41b..1f660de06ea1 100644
--- a/assets/images/cardicons/regions-bank.svg
+++ b/assets/images/cardicons/regions-bank.svg
@@ -1,45 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/suntrust.svg b/assets/images/cardicons/suntrust.svg
index 32ea5096f876..32adeea64cc6 100644
--- a/assets/images/cardicons/suntrust.svg
+++ b/assets/images/cardicons/suntrust.svg
@@ -1,237 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/td-bank.svg b/assets/images/cardicons/td-bank.svg
index 19988e35bbbe..f75f610816d3 100644
--- a/assets/images/cardicons/td-bank.svg
+++ b/assets/images/cardicons/td-bank.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/us-bank.svg b/assets/images/cardicons/us-bank.svg
index 321b4cb755b0..9a1af062c720 100644
--- a/assets/images/cardicons/us-bank.svg
+++ b/assets/images/cardicons/us-bank.svg
@@ -1,32 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cardicons/usaa.svg b/assets/images/cardicons/usaa.svg
index bb634f64e658..d58db9e750c8 100644
--- a/assets/images/cardicons/usaa.svg
+++ b/assets/images/cardicons/usaa.svg
@@ -1,40 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/cash.svg b/assets/images/cash.svg
index 7780e9be9eec..ff4f3fc69664 100644
--- a/assets/images/cash.svg
+++ b/assets/images/cash.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/chair.svg b/assets/images/chair.svg
index d8864d205b33..4ee59941e204 100644
--- a/assets/images/chair.svg
+++ b/assets/images/chair.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/chatbubble.svg b/assets/images/chatbubble.svg
index 23bc4b429ea0..e6863cbd502a 100644
--- a/assets/images/chatbubble.svg
+++ b/assets/images/chatbubble.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/chatbubbles.svg b/assets/images/chatbubbles.svg
index 6194c43e631e..9aca0a7dd8ed 100644
--- a/assets/images/chatbubbles.svg
+++ b/assets/images/chatbubbles.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/checkmark.svg b/assets/images/checkmark.svg
index 7ac28068ff56..8b50271e4419 100644
--- a/assets/images/checkmark.svg
+++ b/assets/images/checkmark.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/close.svg b/assets/images/close.svg
index f36b0714385a..849fce4abb8e 100644
--- a/assets/images/close.svg
+++ b/assets/images/close.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/closed-sign.svg b/assets/images/closed-sign.svg
index 6454e31cd35e..653abe86d2fc 100644
--- a/assets/images/closed-sign.svg
+++ b/assets/images/closed-sign.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/collapse.svg b/assets/images/collapse.svg
index 9b254182dbe2..ea917e4ee827 100644
--- a/assets/images/collapse.svg
+++ b/assets/images/collapse.svg
@@ -1,8 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/concierge.svg b/assets/images/concierge.svg
index 2ed0becb61da..70c91bf3fbb5 100644
--- a/assets/images/concierge.svg
+++ b/assets/images/concierge.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/connect.svg b/assets/images/connect.svg
index e30231e46840..3460bafd5596 100644
--- a/assets/images/connect.svg
+++ b/assets/images/connect.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/copy.svg b/assets/images/copy.svg
index 87707f0be6c1..fa53b2b20ffc 100644
--- a/assets/images/copy.svg
+++ b/assets/images/copy.svg
@@ -1,7 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/creditcard.svg b/assets/images/creditcard.svg
index f174472a63c4..d2fd84adaf58 100644
--- a/assets/images/creditcard.svg
+++ b/assets/images/creditcard.svg
@@ -1,7 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/document.svg b/assets/images/document.svg
index 8ef6c5ec10ce..a4f3c248c266 100644
--- a/assets/images/document.svg
+++ b/assets/images/document.svg
@@ -1,8 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/dot-indicator-unfilled.svg b/assets/images/dot-indicator-unfilled.svg
index ae131b1c2cba..d74c4dff1592 100644
--- a/assets/images/dot-indicator-unfilled.svg
+++ b/assets/images/dot-indicator-unfilled.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/dot-indicator.svg b/assets/images/dot-indicator.svg
index 9d808d91babe..b6565407807f 100644
--- a/assets/images/dot-indicator.svg
+++ b/assets/images/dot-indicator.svg
@@ -1,6 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/down.svg b/assets/images/down.svg
index e4bb5bea9b4d..28d80840f322 100644
--- a/assets/images/down.svg
+++ b/assets/images/down.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/download.svg b/assets/images/download.svg
index 581f504611cc..d3d3b554b990 100644
--- a/assets/images/download.svg
+++ b/assets/images/download.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/drag-and-drop.svg b/assets/images/drag-and-drop.svg
index 8e9251ff3ae5..154ad34f061d 100644
--- a/assets/images/drag-and-drop.svg
+++ b/assets/images/drag-and-drop.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/drag-handles.svg b/assets/images/drag-handles.svg
index ec4fc4ccc672..9951d95cb612 100644
--- a/assets/images/drag-handles.svg
+++ b/assets/images/drag-handles.svg
@@ -1,7 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/eReceipt-BGImage.svg b/assets/images/eReceipt-BGImage.svg
index 48aa548ad6ee..bf89dd853ac8 100644
--- a/assets/images/eReceipt-BGImage.svg
+++ b/assets/images/eReceipt-BGImage.svg
@@ -1,314 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/eReceiptBGs/eReceiptBG_blue.png b/assets/images/eReceiptBGs/eReceiptBG_blue.png
index f317b72dc4fc..602efe533162 100644
Binary files a/assets/images/eReceiptBGs/eReceiptBG_blue.png and b/assets/images/eReceiptBGs/eReceiptBG_blue.png differ
diff --git a/assets/images/eReceiptBGs/eReceiptBG_green.png b/assets/images/eReceiptBGs/eReceiptBG_green.png
index 55fe8886bca9..cf7ae9c58d87 100644
Binary files a/assets/images/eReceiptBGs/eReceiptBG_green.png and b/assets/images/eReceiptBGs/eReceiptBG_green.png differ
diff --git a/assets/images/eReceiptBGs/eReceiptBG_navy.png b/assets/images/eReceiptBGs/eReceiptBG_navy.png
index 2b9616d42c11..0f9449bb26a0 100644
Binary files a/assets/images/eReceiptBGs/eReceiptBG_navy.png and b/assets/images/eReceiptBGs/eReceiptBG_navy.png differ
diff --git a/assets/images/eReceiptBGs/eReceiptBG_pink.png b/assets/images/eReceiptBGs/eReceiptBG_pink.png
index 41b6492c3a35..0fd2ebdd5c6e 100644
Binary files a/assets/images/eReceiptBGs/eReceiptBG_pink.png and b/assets/images/eReceiptBGs/eReceiptBG_pink.png differ
diff --git a/assets/images/eReceiptBGs/eReceiptBG_tangerine.png b/assets/images/eReceiptBGs/eReceiptBG_tangerine.png
index 00a8cd6dd612..3f7e61b04969 100644
Binary files a/assets/images/eReceiptBGs/eReceiptBG_tangerine.png and b/assets/images/eReceiptBGs/eReceiptBG_tangerine.png differ
diff --git a/assets/images/eReceiptBGs/eReceiptBG_yellow.png b/assets/images/eReceiptBGs/eReceiptBG_yellow.png
index 7eb9d1f87fa6..c0c6df3d5748 100644
Binary files a/assets/images/eReceiptBGs/eReceiptBG_yellow.png and b/assets/images/eReceiptBGs/eReceiptBG_yellow.png differ
diff --git a/assets/images/eReceiptIcon.svg b/assets/images/eReceiptIcon.svg
index e54c3a106a48..9b0612a03231 100644
--- a/assets/images/eReceiptIcon.svg
+++ b/assets/images/eReceiptIcon.svg
@@ -1,6 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/eReceipt_background.svg b/assets/images/eReceipt_background.svg
index 5070ed3b2f24..6fadeb352d9b 100644
--- a/assets/images/eReceipt_background.svg
+++ b/assets/images/eReceipt_background.svg
@@ -1,1635 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emoji.svg b/assets/images/emoji.svg
index 431f46962bd7..3b419b40fdf2 100644
--- a/assets/images/emoji.svg
+++ b/assets/images/emoji.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/add-emoji.svg b/assets/images/emojiCategoryIcons/add-emoji.svg
index 5cec67508e4b..e7dd57a0c282 100644
--- a/assets/images/emojiCategoryIcons/add-emoji.svg
+++ b/assets/images/emojiCategoryIcons/add-emoji.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/calendar.svg b/assets/images/emojiCategoryIcons/calendar.svg
index 18885029a7c8..f855bbad61eb 100644
--- a/assets/images/emojiCategoryIcons/calendar.svg
+++ b/assets/images/emojiCategoryIcons/calendar.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/car.svg b/assets/images/emojiCategoryIcons/car.svg
index e5cde58b2615..6c765f34c2da 100644
--- a/assets/images/emojiCategoryIcons/car.svg
+++ b/assets/images/emojiCategoryIcons/car.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/flag.svg b/assets/images/emojiCategoryIcons/flag.svg
index e72787c3665b..5a57ac004991 100644
--- a/assets/images/emojiCategoryIcons/flag.svg
+++ b/assets/images/emojiCategoryIcons/flag.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/hamburger.svg b/assets/images/emojiCategoryIcons/hamburger.svg
index 52945988effc..adc0ff0ed089 100644
--- a/assets/images/emojiCategoryIcons/hamburger.svg
+++ b/assets/images/emojiCategoryIcons/hamburger.svg
@@ -1,8 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/heart.svg b/assets/images/emojiCategoryIcons/heart.svg
index 95e73f329cfa..761bf2770a1e 100644
--- a/assets/images/emojiCategoryIcons/heart.svg
+++ b/assets/images/emojiCategoryIcons/heart.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/light-bulb.svg b/assets/images/emojiCategoryIcons/light-bulb.svg
index 0e6a33c041df..b3b8927786c3 100644
--- a/assets/images/emojiCategoryIcons/light-bulb.svg
+++ b/assets/images/emojiCategoryIcons/light-bulb.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/peace-sign.svg b/assets/images/emojiCategoryIcons/peace-sign.svg
index ab76642fc48d..1015298d7b2c 100644
--- a/assets/images/emojiCategoryIcons/peace-sign.svg
+++ b/assets/images/emojiCategoryIcons/peace-sign.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/plane.svg b/assets/images/emojiCategoryIcons/plane.svg
index 17aca931f8a3..7c989b2e802b 100644
--- a/assets/images/emojiCategoryIcons/plane.svg
+++ b/assets/images/emojiCategoryIcons/plane.svg
@@ -1,8 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/plant.svg b/assets/images/emojiCategoryIcons/plant.svg
index a17ed231e1df..b28f95109299 100644
--- a/assets/images/emojiCategoryIcons/plant.svg
+++ b/assets/images/emojiCategoryIcons/plant.svg
@@ -1,8 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emojiCategoryIcons/soccer-ball.svg b/assets/images/emojiCategoryIcons/soccer-ball.svg
index 40fa05516a11..d5eeb4bf9b7a 100644
--- a/assets/images/emojiCategoryIcons/soccer-ball.svg
+++ b/assets/images/emojiCategoryIcons/soccer-ball.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/emptystate__routepending.svg b/assets/images/emptystate__routepending.svg
index 7646917046cc..90f3296d37d6 100644
--- a/assets/images/emptystate__routepending.svg
+++ b/assets/images/emptystate__routepending.svg
@@ -1,43 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/example-check-image-en.png b/assets/images/example-check-image-en.png
index 2a4f32ade69a..903618776cdf 100644
Binary files a/assets/images/example-check-image-en.png and b/assets/images/example-check-image-en.png differ
diff --git a/assets/images/example-check-image-es.png b/assets/images/example-check-image-es.png
index 435151525a7e..de695a43833d 100644
Binary files a/assets/images/example-check-image-es.png and b/assets/images/example-check-image-es.png differ
diff --git a/assets/images/exclamation.svg b/assets/images/exclamation.svg
index ab70c6f3ca8f..8c55e9667a46 100644
--- a/assets/images/exclamation.svg
+++ b/assets/images/exclamation.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/exit.svg b/assets/images/exit.svg
index 07792548c8a5..8e466eea3608 100644
--- a/assets/images/exit.svg
+++ b/assets/images/exit.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expand.svg b/assets/images/expand.svg
index 0d5d520e444a..25d79d849b58 100644
--- a/assets/images/expand.svg
+++ b/assets/images/expand.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-app-icon.svg b/assets/images/expensify-app-icon.svg
index a0adfe7dd952..f7ae8b487027 100644
--- a/assets/images/expensify-app-icon.svg
+++ b/assets/images/expensify-app-icon.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-card.svg b/assets/images/expensify-card.svg
index f95e3ed20288..52f55778b2bd 100644
--- a/assets/images/expensify-card.svg
+++ b/assets/images/expensify-card.svg
@@ -1,69 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-footer-logo-vertical.svg b/assets/images/expensify-footer-logo-vertical.svg
index 58dc05ad2944..9cd5e26cc8f2 100644
--- a/assets/images/expensify-footer-logo-vertical.svg
+++ b/assets/images/expensify-footer-logo-vertical.svg
@@ -1,30 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-footer-logo.svg b/assets/images/expensify-footer-logo.svg
index e664651b84fd..9e3f837f7365 100644
--- a/assets/images/expensify-footer-logo.svg
+++ b/assets/images/expensify-footer-logo.svg
@@ -1,30 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-logo--adhoc.svg b/assets/images/expensify-logo--adhoc.svg
index 63b6f896e3a5..70d9526ee5f8 100644
--- a/assets/images/expensify-logo--adhoc.svg
+++ b/assets/images/expensify-logo--adhoc.svg
@@ -1,47 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-logo--dev.svg b/assets/images/expensify-logo--dev.svg
index f68fafbad806..92dad9f6d530 100644
--- a/assets/images/expensify-logo--dev.svg
+++ b/assets/images/expensify-logo--dev.svg
@@ -1,42 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-logo--staging.svg b/assets/images/expensify-logo--staging.svg
index 12b0b9bf6e79..22cbba2368e5 100644
--- a/assets/images/expensify-logo--staging.svg
+++ b/assets/images/expensify-logo--staging.svg
@@ -1,45 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify-logo-round-clearspace.png b/assets/images/expensify-logo-round-clearspace.png
index da0f19dda770..2ccb9a39752d 100644
Binary files a/assets/images/expensify-logo-round-clearspace.png and b/assets/images/expensify-logo-round-clearspace.png differ
diff --git a/assets/images/expensify-logo-round-dark.png b/assets/images/expensify-logo-round-dark.png
index 106d28274fd3..a1de022315d9 100644
Binary files a/assets/images/expensify-logo-round-dark.png and b/assets/images/expensify-logo-round-dark.png differ
diff --git a/assets/images/expensify-logo-round-transparent.png b/assets/images/expensify-logo-round-transparent.png
index cfad187e38ef..b2ff00112590 100644
Binary files a/assets/images/expensify-logo-round-transparent.png and b/assets/images/expensify-logo-round-transparent.png differ
diff --git a/assets/images/expensify-logo-round.png b/assets/images/expensify-logo-round.png
index 59d29ed09530..bc97e70dd83b 100644
Binary files a/assets/images/expensify-logo-round.png and b/assets/images/expensify-logo-round.png differ
diff --git a/assets/images/expensify-wordmark.svg b/assets/images/expensify-wordmark.svg
index 69fbcbae6743..da9c93f21e8c 100644
--- a/assets/images/expensify-wordmark.svg
+++ b/assets/images/expensify-wordmark.svg
@@ -1,23 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensify_wordmark_white.svg b/assets/images/expensify_wordmark_white.svg
index 1ad7640b2602..008cfe625591 100644
--- a/assets/images/expensify_wordmark_white.svg
+++ b/assets/images/expensify_wordmark_white.svg
@@ -1,26 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/expensifycard.svg b/assets/images/expensifycard.svg
index c146a4709e94..8e20d27af48c 100644
--- a/assets/images/expensifycard.svg
+++ b/assets/images/expensifycard.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/eye-disabled.svg b/assets/images/eye-disabled.svg
index 4055ba7e78a0..2537205a19da 100644
--- a/assets/images/eye-disabled.svg
+++ b/assets/images/eye-disabled.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/eye.svg b/assets/images/eye.svg
index dd0a4fd532b8..79c9f18e68f9 100644
--- a/assets/images/eye.svg
+++ b/assets/images/eye.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/flag.svg b/assets/images/flag.svg
index 9b6737459fbd..5a57ac004991 100644
--- a/assets/images/flag.svg
+++ b/assets/images/flag.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/flag_level_01.svg b/assets/images/flag_level_01.svg
index a4259deb0d2c..e77b84819777 100644
--- a/assets/images/flag_level_01.svg
+++ b/assets/images/flag_level_01.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/flag_level_02.svg b/assets/images/flag_level_02.svg
index 9d7010dbb7f9..c31ac07e2886 100644
--- a/assets/images/flag_level_02.svg
+++ b/assets/images/flag_level_02.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/flag_level_03.svg b/assets/images/flag_level_03.svg
index 14fc80792cc2..a156e13c2c74 100644
--- a/assets/images/flag_level_03.svg
+++ b/assets/images/flag_level_03.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/gallery.svg b/assets/images/gallery.svg
index 21eb78059329..6d061e77c658 100644
--- a/assets/images/gallery.svg
+++ b/assets/images/gallery.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/gear.svg b/assets/images/gear.svg
index f7090075e0a4..234d60a31ae5 100644
--- a/assets/images/gear.svg
+++ b/assets/images/gear.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/globe.svg b/assets/images/globe.svg
index f057bd36379b..b6f802d72435 100644
--- a/assets/images/globe.svg
+++ b/assets/images/globe.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/google-meet.svg b/assets/images/google-meet.svg
index 980cd102f67a..8def88aa6edc 100644
--- a/assets/images/google-meet.svg
+++ b/assets/images/google-meet.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/hand.svg b/assets/images/hand.svg
index e9a56d260ed0..047af1d67ed8 100644
--- a/assets/images/hand.svg
+++ b/assets/images/hand.svg
@@ -1,196 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/hashtag.svg b/assets/images/hashtag.svg
index 86324ffcdba8..00d0a253659a 100644
--- a/assets/images/hashtag.svg
+++ b/assets/images/hashtag.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/heart.svg b/assets/images/heart.svg
index 95e73f329cfa..761bf2770a1e 100644
--- a/assets/images/heart.svg
+++ b/assets/images/heart.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/history.svg b/assets/images/history.svg
index 5eefb04b480d..09be03108312 100644
--- a/assets/images/history.svg
+++ b/assets/images/history.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/home-background--desktop.svg b/assets/images/home-background--desktop.svg
index c577609efb3b..4d1c18fb3ba7 100644
--- a/assets/images/home-background--desktop.svg
+++ b/assets/images/home-background--desktop.svg
@@ -1,8835 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/home-background--mobile.svg b/assets/images/home-background--mobile.svg
index 0af3aac59146..7c4d4d8289b7 100644
--- a/assets/images/home-background--mobile.svg
+++ b/assets/images/home-background--mobile.svg
@@ -1,6556 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/home-fade-gradient--mobile.svg b/assets/images/home-fade-gradient--mobile.svg
index ca03eb3323af..0b24b678a2e6 100644
--- a/assets/images/home-fade-gradient--mobile.svg
+++ b/assets/images/home-fade-gradient--mobile.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/home-fade-gradient.svg b/assets/images/home-fade-gradient.svg
index 6aada6633a8b..bfe04d545364 100644
--- a/assets/images/home-fade-gradient.svg
+++ b/assets/images/home-fade-gradient.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/hourglass.svg b/assets/images/hourglass.svg
index b04dc3589d73..a04084dca1f5 100644
--- a/assets/images/hourglass.svg
+++ b/assets/images/hourglass.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/image-crop-circle-mask.svg b/assets/images/image-crop-circle-mask.svg
index 8edded23218d..491adb0a7248 100644
--- a/assets/images/image-crop-circle-mask.svg
+++ b/assets/images/image-crop-circle-mask.svg
@@ -1,23 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/image-crop-square-mask.svg b/assets/images/image-crop-square-mask.svg
index 050998d576f8..947c99987f9b 100644
--- a/assets/images/image-crop-square-mask.svg
+++ b/assets/images/image-crop-square-mask.svg
@@ -1,24 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/info.svg b/assets/images/info.svg
index 7446622ab044..da3fa688b44e 100644
--- a/assets/images/info.svg
+++ b/assets/images/info.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/invoice.svg b/assets/images/invoice.svg
index 618aba9be614..0ea93b1b8e2b 100644
--- a/assets/images/invoice.svg
+++ b/assets/images/invoice.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/key.svg b/assets/images/key.svg
index 595a1541ce5e..b25879191ac9 100644
--- a/assets/images/key.svg
+++ b/assets/images/key.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/keyboard.svg b/assets/images/keyboard.svg
index 16df73f0026b..f6040430fcb4 100644
--- a/assets/images/keyboard.svg
+++ b/assets/images/keyboard.svg
@@ -1,20 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/link-copy.svg b/assets/images/link-copy.svg
index e153fbc49795..a23593e79eab 100644
--- a/assets/images/link-copy.svg
+++ b/assets/images/link-copy.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/link.svg b/assets/images/link.svg
index a284470a5c79..abfac3a2d180 100644
--- a/assets/images/link.svg
+++ b/assets/images/link.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/location.svg b/assets/images/location.svg
index ad8102051e26..fa00dafbcbfe 100644
--- a/assets/images/location.svg
+++ b/assets/images/location.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/lock.svg b/assets/images/lock.svg
index ab4bafc4724d..9b4c17c6dea9 100644
--- a/assets/images/lock.svg
+++ b/assets/images/lock.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/luggage.svg b/assets/images/luggage.svg
index 65edc1f31fb3..46453be7c392 100644
--- a/assets/images/luggage.svg
+++ b/assets/images/luggage.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/magnifying-glass.svg b/assets/images/magnifying-glass.svg
index c0e2465f0308..d8457b870bc8 100644
--- a/assets/images/magnifying-glass.svg
+++ b/assets/images/magnifying-glass.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/mail.svg b/assets/images/mail.svg
index 1a3d788288b9..9963b0cfb84a 100644
--- a/assets/images/mail.svg
+++ b/assets/images/mail.svg
@@ -1,8 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/megaphone.svg b/assets/images/megaphone.svg
index a10a6d838558..45e905d3f3e3 100644
--- a/assets/images/megaphone.svg
+++ b/assets/images/megaphone.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/menu.svg b/assets/images/menu.svg
index 9995bb6d521b..c0a7e3aa7b68 100644
--- a/assets/images/menu.svg
+++ b/assets/images/menu.svg
@@ -1,8 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/money-bag.svg b/assets/images/money-bag.svg
index e691635f9544..e02865e5aff9 100644
--- a/assets/images/money-bag.svg
+++ b/assets/images/money-bag.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/money-circle.svg b/assets/images/money-circle.svg
index f6c66e0a6dfb..28783d0f78a7 100644
--- a/assets/images/money-circle.svg
+++ b/assets/images/money-circle.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/money-stack.svg b/assets/images/money-stack.svg
index b9a93c76198c..587180bb11d6 100644
--- a/assets/images/money-stack.svg
+++ b/assets/images/money-stack.svg
@@ -1,125 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/monitor.svg b/assets/images/monitor.svg
index a8b99721a9cc..d5c74474b524 100644
--- a/assets/images/monitor.svg
+++ b/assets/images/monitor.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/new-expensify-adhoc.svg b/assets/images/new-expensify-adhoc.svg
index d3a926a097ec..f2603555fc38 100644
--- a/assets/images/new-expensify-adhoc.svg
+++ b/assets/images/new-expensify-adhoc.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/new-expensify-dark.svg b/assets/images/new-expensify-dark.svg
index ad34f1d9dfce..01967175139b 100644
--- a/assets/images/new-expensify-dark.svg
+++ b/assets/images/new-expensify-dark.svg
@@ -1,10 +1 @@
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/new-expensify-dev.svg b/assets/images/new-expensify-dev.svg
index 423fe56c98b7..9c11ed02433c 100644
--- a/assets/images/new-expensify-dev.svg
+++ b/assets/images/new-expensify-dev.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/new-expensify-stg.svg b/assets/images/new-expensify-stg.svg
index 61852bbb1932..f151d7c4c130 100644
--- a/assets/images/new-expensify-stg.svg
+++ b/assets/images/new-expensify-stg.svg
@@ -1,48 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/new-expensify.svg b/assets/images/new-expensify.svg
index dc8273e6aa99..38276ecd9385 100644
--- a/assets/images/new-expensify.svg
+++ b/assets/images/new-expensify.svg
@@ -1,29 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/new-window.svg b/assets/images/new-window.svg
index c1b9991558b7..5f8212a20197 100644
--- a/assets/images/new-window.svg
+++ b/assets/images/new-window.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/new-workspace.svg b/assets/images/new-workspace.svg
index 62f4717108e9..e50136e34355 100644
--- a/assets/images/new-workspace.svg
+++ b/assets/images/new-workspace.svg
@@ -1,19 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/offline-cloud.svg b/assets/images/offline-cloud.svg
index ae8305e52934..cb789b6ad5be 100644
--- a/assets/images/offline-cloud.svg
+++ b/assets/images/offline-cloud.svg
@@ -1,8 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/offline.svg b/assets/images/offline.svg
index 21cb29d382c0..daf4370ab7c1 100644
--- a/assets/images/offline.svg
+++ b/assets/images/offline.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/paperclip.svg b/assets/images/paperclip.svg
index 29760284c687..6421040301a0 100644
--- a/assets/images/paperclip.svg
+++ b/assets/images/paperclip.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/paycheck.svg b/assets/images/paycheck.svg
index d54602d8b11b..f607e34833a1 100644
--- a/assets/images/paycheck.svg
+++ b/assets/images/paycheck.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/paypal.svg b/assets/images/paypal.svg
index 370a55b41284..4aaccc60c21c 100644
--- a/assets/images/paypal.svg
+++ b/assets/images/paypal.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/pencil.svg b/assets/images/pencil.svg
index 8673005d818a..2f1f8354d3b5 100644
--- a/assets/images/pencil.svg
+++ b/assets/images/pencil.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/phone.svg b/assets/images/phone.svg
index 38cc8c1319dc..22492a8a81c2 100644
--- a/assets/images/phone.svg
+++ b/assets/images/phone.svg
@@ -1,8 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/pin.svg b/assets/images/pin.svg
index 048f95cbc929..7d2e62687344 100644
--- a/assets/images/pin.svg
+++ b/assets/images/pin.svg
@@ -1,9 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/plus.svg b/assets/images/plus.svg
index 59a0b803dde4..9d658b6bbea7 100644
--- a/assets/images/plus.svg
+++ b/assets/images/plus.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/printer.svg b/assets/images/printer.svg
index ce0d725d4251..b231412ddebe 100644
--- a/assets/images/printer.svg
+++ b/assets/images/printer.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/abracadabra.svg b/assets/images/product-illustrations/abracadabra.svg
index dba7336cd11d..3eb20add6066 100644
--- a/assets/images/product-illustrations/abracadabra.svg
+++ b/assets/images/product-illustrations/abracadabra.svg
@@ -1,710 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/bank-arrow--pink.svg b/assets/images/product-illustrations/bank-arrow--pink.svg
index c561bfd2790d..a7d6668d4d9d 100644
--- a/assets/images/product-illustrations/bank-arrow--pink.svg
+++ b/assets/images/product-illustrations/bank-arrow--pink.svg
@@ -1,43 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/bank-mouse--green.svg b/assets/images/product-illustrations/bank-mouse--green.svg
index 99dfd1718c1e..b7cfc91bbd46 100644
--- a/assets/images/product-illustrations/bank-mouse--green.svg
+++ b/assets/images/product-illustrations/bank-mouse--green.svg
@@ -1,50 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/bank-user--green.svg b/assets/images/product-illustrations/bank-user--green.svg
index 676d05c3bc0c..35029902801c 100644
--- a/assets/images/product-illustrations/bank-user--green.svg
+++ b/assets/images/product-illustrations/bank-user--green.svg
@@ -1,48 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/concierge--blue.svg b/assets/images/product-illustrations/concierge--blue.svg
index d1d3fede1f64..facba4991d05 100644
--- a/assets/images/product-illustrations/concierge--blue.svg
+++ b/assets/images/product-illustrations/concierge--blue.svg
@@ -1,20 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/concierge--exclamation.svg b/assets/images/product-illustrations/concierge--exclamation.svg
index ed4b8fd3f533..8033d84b1a5a 100644
--- a/assets/images/product-illustrations/concierge--exclamation.svg
+++ b/assets/images/product-illustrations/concierge--exclamation.svg
@@ -1,26 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/credit-cards--blue.svg b/assets/images/product-illustrations/credit-cards--blue.svg
index 008dbd20be30..51f18537af1a 100644
--- a/assets/images/product-illustrations/credit-cards--blue.svg
+++ b/assets/images/product-illustrations/credit-cards--blue.svg
@@ -1,31 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/gps-track--orange.svg b/assets/images/product-illustrations/gps-track--orange.svg
index 400958af31ca..1c13895e27fb 100644
--- a/assets/images/product-illustrations/gps-track--orange.svg
+++ b/assets/images/product-illustrations/gps-track--orange.svg
@@ -1,24 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/home-illustration-hands.svg b/assets/images/product-illustrations/home-illustration-hands.svg
index 9a70d8cc6363..75ee67189126 100644
--- a/assets/images/product-illustrations/home-illustration-hands.svg
+++ b/assets/images/product-illustrations/home-illustration-hands.svg
@@ -1,545 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/invoice--orange.svg b/assets/images/product-illustrations/invoice--orange.svg
index aebd50660662..0512cfd2959f 100644
--- a/assets/images/product-illustrations/invoice--orange.svg
+++ b/assets/images/product-illustrations/invoice--orange.svg
@@ -1,25 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/jewel-box--blue.svg b/assets/images/product-illustrations/jewel-box--blue.svg
index b9d6a084bcb9..c137a0063b5f 100644
--- a/assets/images/product-illustrations/jewel-box--blue.svg
+++ b/assets/images/product-illustrations/jewel-box--blue.svg
@@ -1,45 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/jewel-box--green.svg b/assets/images/product-illustrations/jewel-box--green.svg
index ba1cade3dcc3..c4c73385b636 100644
--- a/assets/images/product-illustrations/jewel-box--green.svg
+++ b/assets/images/product-illustrations/jewel-box--green.svg
@@ -1,45 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/jewel-box--pink.svg b/assets/images/product-illustrations/jewel-box--pink.svg
index dd58151c9132..d42baf0c5d8b 100644
--- a/assets/images/product-illustrations/jewel-box--pink.svg
+++ b/assets/images/product-illustrations/jewel-box--pink.svg
@@ -1,45 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/jewel-box--yellow.svg b/assets/images/product-illustrations/jewel-box--yellow.svg
index 858d5b666886..3f40365bd0f1 100644
--- a/assets/images/product-illustrations/jewel-box--yellow.svg
+++ b/assets/images/product-illustrations/jewel-box--yellow.svg
@@ -1,45 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/magic-code.svg b/assets/images/product-illustrations/magic-code.svg
index 7f26cf51874c..f623857f1546 100644
--- a/assets/images/product-illustrations/magic-code.svg
+++ b/assets/images/product-illustrations/magic-code.svg
@@ -1,931 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/money-envelope--blue.svg b/assets/images/product-illustrations/money-envelope--blue.svg
index 199489af882f..78ac4032daf5 100644
--- a/assets/images/product-illustrations/money-envelope--blue.svg
+++ b/assets/images/product-illustrations/money-envelope--blue.svg
@@ -1,30 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/money-mouse--pink.svg b/assets/images/product-illustrations/money-mouse--pink.svg
index 72c21fc46754..ae67d1f8c2b6 100644
--- a/assets/images/product-illustrations/money-mouse--pink.svg
+++ b/assets/images/product-illustrations/money-mouse--pink.svg
@@ -1,30 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/receipt--yellow.svg b/assets/images/product-illustrations/receipt--yellow.svg
index f40f3e0a5aa9..c5e2ea9c07e3 100644
--- a/assets/images/product-illustrations/receipt--yellow.svg
+++ b/assets/images/product-illustrations/receipt--yellow.svg
@@ -1,20 +1 @@
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/receipts-search--yellow.svg b/assets/images/product-illustrations/receipts-search--yellow.svg
index 9db0cc47c236..f40061c034d5 100644
--- a/assets/images/product-illustrations/receipts-search--yellow.svg
+++ b/assets/images/product-illustrations/receipts-search--yellow.svg
@@ -1,55 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/rocket--blue.svg b/assets/images/product-illustrations/rocket--blue.svg
index b59e8a28c8ca..5fec253cc4e1 100644
--- a/assets/images/product-illustrations/rocket--blue.svg
+++ b/assets/images/product-illustrations/rocket--blue.svg
@@ -1,286 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/rocket--orange.svg b/assets/images/product-illustrations/rocket--orange.svg
index a3bb9a67fb7d..0e8078e926f4 100644
--- a/assets/images/product-illustrations/rocket--orange.svg
+++ b/assets/images/product-illustrations/rocket--orange.svg
@@ -1,87 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/safe.svg b/assets/images/product-illustrations/safe.svg
index db2ac0707f7f..70e6d116daa9 100644
--- a/assets/images/product-illustrations/safe.svg
+++ b/assets/images/product-illustrations/safe.svg
@@ -1,119 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/simple-illustration__smartscan.svg b/assets/images/product-illustrations/simple-illustration__smartscan.svg
index 34d1fadfaa3b..688133368956 100644
--- a/assets/images/product-illustrations/simple-illustration__smartscan.svg
+++ b/assets/images/product-illustrations/simple-illustration__smartscan.svg
@@ -1,21 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/tada--blue.svg b/assets/images/product-illustrations/tada--blue.svg
index 5430863ca145..c0f2b3f104eb 100644
--- a/assets/images/product-illustrations/tada--blue.svg
+++ b/assets/images/product-illustrations/tada--blue.svg
@@ -1,54 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/tada--yellow.svg b/assets/images/product-illustrations/tada--yellow.svg
index 037baef7defe..b21887899768 100644
--- a/assets/images/product-illustrations/tada--yellow.svg
+++ b/assets/images/product-illustrations/tada--yellow.svg
@@ -1,56 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/product-illustrations/todd-behind-cloud.svg b/assets/images/product-illustrations/todd-behind-cloud.svg
index 6281ce0ef727..65911b275499 100644
--- a/assets/images/product-illustrations/todd-behind-cloud.svg
+++ b/assets/images/product-illustrations/todd-behind-cloud.svg
@@ -1,58 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/profile.svg b/assets/images/profile.svg
index 9f41da0e141f..84edb572b236 100644
--- a/assets/images/profile.svg
+++ b/assets/images/profile.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/qrcode.svg b/assets/images/qrcode.svg
index 8851a69a03d7..f506a944d54e 100644
--- a/assets/images/qrcode.svg
+++ b/assets/images/qrcode.svg
@@ -1,5 +1 @@
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/question-mark-circle.svg b/assets/images/question-mark-circle.svg
index ae318f655750..cd42f3c118d3 100644
--- a/assets/images/question-mark-circle.svg
+++ b/assets/images/question-mark-circle.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/receipt-doc.png b/assets/images/receipt-doc.png
index 773bfaed73ad..4c9ced0356a3 100644
Binary files a/assets/images/receipt-doc.png and b/assets/images/receipt-doc.png differ
diff --git a/assets/images/receipt-generic.png b/assets/images/receipt-generic.png
index 1aabe854617d..d0ac937ac777 100644
Binary files a/assets/images/receipt-generic.png and b/assets/images/receipt-generic.png differ
diff --git a/assets/images/receipt-html.png b/assets/images/receipt-html.png
index 5cf8d585b21f..cade062115f2 100644
Binary files a/assets/images/receipt-html.png and b/assets/images/receipt-html.png differ
diff --git a/assets/images/receipt-search.svg b/assets/images/receipt-search.svg
index a8aa5f51f581..f79866cae6a5 100644
--- a/assets/images/receipt-search.svg
+++ b/assets/images/receipt-search.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/receipt-svg.png b/assets/images/receipt-svg.png
index 130c331dd8c9..c0306e94827f 100644
Binary files a/assets/images/receipt-svg.png and b/assets/images/receipt-svg.png differ
diff --git a/assets/images/receipt-upload.svg b/assets/images/receipt-upload.svg
index 813aaac51f5b..d008c2999dae 100644
--- a/assets/images/receipt-upload.svg
+++ b/assets/images/receipt-upload.svg
@@ -1,110 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/receipt.svg b/assets/images/receipt.svg
index 5ad963dab8ad..0983f6fec369 100644
--- a/assets/images/receipt.svg
+++ b/assets/images/receipt.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/rotate-image.svg b/assets/images/rotate-image.svg
index b1c4f02cbb8d..c3cb0e0293bf 100644
--- a/assets/images/rotate-image.svg
+++ b/assets/images/rotate-image.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/rotate-left.svg b/assets/images/rotate-left.svg
index 47447cf91cf9..935cbf93757f 100644
--- a/assets/images/rotate-left.svg
+++ b/assets/images/rotate-left.svg
@@ -1,8 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/rotate.svg b/assets/images/rotate.svg
index 651f9a6ac82d..f9eb97017020 100644
--- a/assets/images/rotate.svg
+++ b/assets/images/rotate.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/send.svg b/assets/images/send.svg
index 9ba1c6a336a2..34327fab329f 100644
--- a/assets/images/send.svg
+++ b/assets/images/send.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/shield.svg b/assets/images/shield.svg
index cb46f32fdfa0..09d5c7d51252 100644
--- a/assets/images/shield.svg
+++ b/assets/images/shield.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/shutter.svg b/assets/images/shutter.svg
index e4dadcea8089..f8d81efcee2b 100644
--- a/assets/images/shutter.svg
+++ b/assets/images/shutter.svg
@@ -1,18 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/signIn/apple-logo.svg b/assets/images/signIn/apple-logo.svg
index 4e428fc41aed..de5ebf191066 100644
--- a/assets/images/signIn/apple-logo.svg
+++ b/assets/images/signIn/apple-logo.svg
@@ -1,4 +1 @@
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/signIn/google-logo.svg b/assets/images/signIn/google-logo.svg
index ebdd4be8cade..ec879fafa988 100644
--- a/assets/images/signIn/google-logo.svg
+++ b/assets/images/signIn/google-logo.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__bank-arrow.svg b/assets/images/simple-illustrations/simple-illustration__bank-arrow.svg
index 7e5b4dae1ccc..85a0445f640b 100644
--- a/assets/images/simple-illustrations/simple-illustration__bank-arrow.svg
+++ b/assets/images/simple-illustrations/simple-illustration__bank-arrow.svg
@@ -1,172 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__bill.svg b/assets/images/simple-illustrations/simple-illustration__bill.svg
index 7fb76fb8c09b..aa4cb8fc9faf 100644
--- a/assets/images/simple-illustrations/simple-illustration__bill.svg
+++ b/assets/images/simple-illustrations/simple-illustration__bill.svg
@@ -1,57 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__chatbubbles.svg b/assets/images/simple-illustrations/simple-illustration__chatbubbles.svg
index 8edeea7e06f9..37857c15c074 100644
--- a/assets/images/simple-illustrations/simple-illustration__chatbubbles.svg
+++ b/assets/images/simple-illustrations/simple-illustration__chatbubbles.svg
@@ -1,24 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__coffeemug.svg b/assets/images/simple-illustrations/simple-illustration__coffeemug.svg
index de4ae88d731b..7d54b9892fce 100644
--- a/assets/images/simple-illustrations/simple-illustration__coffeemug.svg
+++ b/assets/images/simple-illustrations/simple-illustration__coffeemug.svg
@@ -1,46 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__concierge-bubble.svg b/assets/images/simple-illustrations/simple-illustration__concierge-bubble.svg
index eeabc78b1881..b3a6bf98deba 100644
--- a/assets/images/simple-illustrations/simple-illustration__concierge-bubble.svg
+++ b/assets/images/simple-illustrations/simple-illustration__concierge-bubble.svg
@@ -1,102 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__concierge.svg b/assets/images/simple-illustrations/simple-illustration__concierge.svg
index 8275671c3486..061a37d492e9 100644
--- a/assets/images/simple-illustrations/simple-illustration__concierge.svg
+++ b/assets/images/simple-illustrations/simple-illustration__concierge.svg
@@ -1,95 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__credit-cards.svg b/assets/images/simple-illustrations/simple-illustration__credit-cards.svg
index 8e070f074ef3..f0ffd1174efc 100644
--- a/assets/images/simple-illustrations/simple-illustration__credit-cards.svg
+++ b/assets/images/simple-illustrations/simple-illustration__credit-cards.svg
@@ -1,92 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__email-address.svg b/assets/images/simple-illustrations/simple-illustration__email-address.svg
index a8f0db9a4f8b..7bf0d253530a 100644
--- a/assets/images/simple-illustrations/simple-illustration__email-address.svg
+++ b/assets/images/simple-illustrations/simple-illustration__email-address.svg
@@ -1,35 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__handearth.svg b/assets/images/simple-illustrations/simple-illustration__handearth.svg
index f79e3f73293b..30828ee3585b 100644
--- a/assets/images/simple-illustrations/simple-illustration__handearth.svg
+++ b/assets/images/simple-illustrations/simple-illustration__handearth.svg
@@ -1,30 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__invoice.svg b/assets/images/simple-illustrations/simple-illustration__invoice.svg
index 0a10b70a7bfe..bd7738e571cd 100644
--- a/assets/images/simple-illustrations/simple-illustration__invoice.svg
+++ b/assets/images/simple-illustrations/simple-illustration__invoice.svg
@@ -1,65 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__lockopen.svg b/assets/images/simple-illustrations/simple-illustration__lockopen.svg
index fb07d7a8628b..6a269e686ab5 100644
--- a/assets/images/simple-illustrations/simple-illustration__lockopen.svg
+++ b/assets/images/simple-illustrations/simple-illustration__lockopen.svg
@@ -1,73 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__luggage.svg b/assets/images/simple-illustrations/simple-illustration__luggage.svg
index 9a01eee56662..3d3118f8cebd 100644
--- a/assets/images/simple-illustrations/simple-illustration__luggage.svg
+++ b/assets/images/simple-illustrations/simple-illustration__luggage.svg
@@ -1,79 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__money-receipts.svg b/assets/images/simple-illustrations/simple-illustration__money-receipts.svg
index 3d81f5dba653..af9d6a26a73a 100644
--- a/assets/images/simple-illustrations/simple-illustration__money-receipts.svg
+++ b/assets/images/simple-illustrations/simple-illustration__money-receipts.svg
@@ -1,142 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__moneybadge.svg b/assets/images/simple-illustrations/simple-illustration__moneybadge.svg
index 1f673aa20a90..68fc7845e531 100644
--- a/assets/images/simple-illustrations/simple-illustration__moneybadge.svg
+++ b/assets/images/simple-illustrations/simple-illustration__moneybadge.svg
@@ -1,78 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg b/assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg
index 3f89e6b14836..e184257a4456 100644
--- a/assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg
+++ b/assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg
@@ -1,137 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__moneywings.svg b/assets/images/simple-illustrations/simple-illustration__moneywings.svg
index b13abdf448af..921af4ff88be 100644
--- a/assets/images/simple-illustrations/simple-illustration__moneywings.svg
+++ b/assets/images/simple-illustrations/simple-illustration__moneywings.svg
@@ -1,131 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__opensafe.svg b/assets/images/simple-illustrations/simple-illustration__opensafe.svg
index 273d68b62723..1dd6ab9e5215 100644
--- a/assets/images/simple-illustrations/simple-illustration__opensafe.svg
+++ b/assets/images/simple-illustrations/simple-illustration__opensafe.svg
@@ -1,195 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__sanfrancisco.svg b/assets/images/simple-illustrations/simple-illustration__sanfrancisco.svg
index 79779e85c940..ef1dfd547614 100644
--- a/assets/images/simple-illustrations/simple-illustration__sanfrancisco.svg
+++ b/assets/images/simple-illustrations/simple-illustration__sanfrancisco.svg
@@ -1,78 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__shield.svg b/assets/images/simple-illustrations/simple-illustration__shield.svg
index 5d56b9c3acb2..ebea008403a0 100644
--- a/assets/images/simple-illustrations/simple-illustration__shield.svg
+++ b/assets/images/simple-illustrations/simple-illustration__shield.svg
@@ -1,77 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg b/assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg
index 623874d2d3eb..23412a17af4a 100644
--- a/assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg
+++ b/assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg
@@ -1,69 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__track-shoe.svg b/assets/images/simple-illustrations/simple-illustration__track-shoe.svg
index 5d45f2f9df67..04679033a714 100644
--- a/assets/images/simple-illustrations/simple-illustration__track-shoe.svg
+++ b/assets/images/simple-illustrations/simple-illustration__track-shoe.svg
@@ -1,100 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/simple-illustrations/simple-illustration__treasurechest.svg b/assets/images/simple-illustrations/simple-illustration__treasurechest.svg
index edb868db11d2..2bdee0c7e90f 100644
--- a/assets/images/simple-illustrations/simple-illustration__treasurechest.svg
+++ b/assets/images/simple-illustrations/simple-illustration__treasurechest.svg
@@ -1,138 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/social-facebook.svg b/assets/images/social-facebook.svg
index 3a966653e688..a8ed9b7c5231 100644
--- a/assets/images/social-facebook.svg
+++ b/assets/images/social-facebook.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/social-instagram.svg b/assets/images/social-instagram.svg
index 79d4aadf374a..a90ae389b0ed 100644
--- a/assets/images/social-instagram.svg
+++ b/assets/images/social-instagram.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/social-linkedin.svg b/assets/images/social-linkedin.svg
index 97a1da8962f4..04a88fa700a9 100644
--- a/assets/images/social-linkedin.svg
+++ b/assets/images/social-linkedin.svg
@@ -1,8 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/social-podcast.svg b/assets/images/social-podcast.svg
index 1366699b6823..41b6905a37b2 100644
--- a/assets/images/social-podcast.svg
+++ b/assets/images/social-podcast.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/social-twitter.svg b/assets/images/social-twitter.svg
index 6a90f95032bb..5955d2ab21de 100644
--- a/assets/images/social-twitter.svg
+++ b/assets/images/social-twitter.svg
@@ -1,9 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/social-youtube.svg b/assets/images/social-youtube.svg
index 834314d27d27..ef8161be32cd 100644
--- a/assets/images/social-youtube.svg
+++ b/assets/images/social-youtube.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/sync.svg b/assets/images/sync.svg
index 65d8df356901..af28fef95b86 100644
--- a/assets/images/sync.svg
+++ b/assets/images/sync.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/task.svg b/assets/images/task.svg
index 20412f771b69..4a51073fece2 100644
--- a/assets/images/task.svg
+++ b/assets/images/task.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/three-dots.svg b/assets/images/three-dots.svg
index 1ff11c8448a1..2c92f2db7820 100644
--- a/assets/images/three-dots.svg
+++ b/assets/images/three-dots.svg
@@ -1,8 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/transfer.svg b/assets/images/transfer.svg
index 76288f8227b4..bc717c0a1c85 100644
--- a/assets/images/transfer.svg
+++ b/assets/images/transfer.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/trashcan.svg b/assets/images/trashcan.svg
index 6158a705bd35..0456e6c94350 100644
--- a/assets/images/trashcan.svg
+++ b/assets/images/trashcan.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/unlock.svg b/assets/images/unlock.svg
index 0cf22e8d1813..22c4278b0072 100644
--- a/assets/images/unlock.svg
+++ b/assets/images/unlock.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/upload-alt.svg b/assets/images/upload-alt.svg
index 3b8e7137bd93..19973e11f98d 100644
--- a/assets/images/upload-alt.svg
+++ b/assets/images/upload-alt.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/upload.svg b/assets/images/upload.svg
index faffc4a9b8cf..fee5f66a1d67 100644
--- a/assets/images/upload.svg
+++ b/assets/images/upload.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/user.svg b/assets/images/user.svg
index 96f403e2ce4a..16672c8b8ed9 100644
--- a/assets/images/user.svg
+++ b/assets/images/user.svg
@@ -1,7 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/users.svg b/assets/images/users.svg
index 8af469328821..ac2ee1ccb83f 100644
--- a/assets/images/users.svg
+++ b/assets/images/users.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/wallet.svg b/assets/images/wallet.svg
index 1c6d606683b8..1e213fe209e1 100644
--- a/assets/images/wallet.svg
+++ b/assets/images/wallet.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/workspace-default-avatar.svg b/assets/images/workspace-default-avatar.svg
index 63d0a47f6806..b853e2ad2520 100644
--- a/assets/images/workspace-default-avatar.svg
+++ b/assets/images/workspace-default-avatar.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/zoom-icon.svg b/assets/images/zoom-icon.svg
index 24d019654795..81f025aedf79 100644
--- a/assets/images/zoom-icon.svg
+++ b/assets/images/zoom-icon.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/assets/images/zoom.svg b/assets/images/zoom.svg
index 25e82c2903eb..a7d1c64556ba 100644
--- a/assets/images/zoom.svg
+++ b/assets/images/zoom.svg
@@ -1,13 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/babel.config.js b/babel.config.js
index 3a49f3bccbe5..189c3379aa6d 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -41,6 +41,42 @@ const metro = {
['@babel/plugin-proposal-private-property-in-object', {loose: true}],
// The reanimated babel plugin needs to be last, as stated here: https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/installation
'react-native-reanimated/plugin',
+ // Import alias for native devices
+ [
+ 'module-resolver',
+ {
+ extensions: [
+ '.native.js',
+ '.native.jsx',
+ '.native.ts',
+ '.native.tsx',
+ '.js',
+ '.jsx',
+ '.ts',
+ '.tsx',
+ '.ios.js',
+ '.ios.jsx',
+ '.ios.ts',
+ '.ios.tsx',
+ '.android.js',
+ '.android.jsx',
+ '.android.ts',
+ '.android.tx',
+ ],
+ alias: {
+ '@assets': './assets',
+ '@components': './src/components',
+ '@hooks': './src/hooks',
+ '@libs': './src/libs',
+ '@navigation': './src/libs/Navigation',
+ '@pages': './src/pages',
+ '@styles': './src/styles',
+ // This path is provide alias for files like `ONYXKEYS` and `CONST`.
+ '@src': './src',
+ '@userActions': './src/libs/actions',
+ },
+ },
+ ],
],
};
diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js
index d8a24adefdc3..a22a9d55b2a3 100644
--- a/config/webpack/webpack.common.js
+++ b/config/webpack/webpack.common.js
@@ -189,6 +189,19 @@ const webpackConfig = ({envFile = '.env', platform = 'web'}) => ({
'react-native-web': '@expensify/react-native-web',
'react-content-loader/native': 'react-content-loader',
'lottie-react-native': 'react-native-web-lottie',
+
+ // Module alias for web & desktop
+ // https://webpack.js.org/configuration/resolve/#resolvealias
+ '@assets': path.resolve(__dirname, '../../assets'),
+ '@components': path.resolve(__dirname, '../../src/components/'),
+ '@hooks': path.resolve(__dirname, '../../src/hooks/'),
+ '@libs': path.resolve(__dirname, '../../src/libs/'),
+ '@navigation': path.resolve(__dirname, '../../src/libs/Navigation/'),
+ '@pages': path.resolve(__dirname, '../../src/pages/'),
+ '@styles': path.resolve(__dirname, '../../src/styles/'),
+ // This path is provide alias for files like `ONYXKEYS` and `CONST`.
+ '@src': path.resolve(__dirname, '../../src/'),
+ '@userActions': path.resolve(__dirname, '../../src/libs/actions/'),
},
// React Native libraries may have web-specific module implementations that appear with the extension `.web.js`
diff --git a/contributingGuides/OfflineUX_Patterns_Flowchart.png b/contributingGuides/OfflineUX_Patterns_Flowchart.png
index 813474dedb0d..bd7a0f311059 100644
Binary files a/contributingGuides/OfflineUX_Patterns_Flowchart.png and b/contributingGuides/OfflineUX_Patterns_Flowchart.png differ
diff --git a/contributingGuides/REVIEWER_CHECKLIST.md b/contributingGuides/REVIEWER_CHECKLIST.md
index d52d80a818bb..16c8f88927b1 100644
--- a/contributingGuides/REVIEWER_CHECKLIST.md
+++ b/contributingGuides/REVIEWER_CHECKLIST.md
@@ -57,42 +57,42 @@
### Screenshots/Videos
-Web
+Android: Native
-Mobile Web - Chrome
+Android: mWeb Chrome
-Mobile Web - Safari
+iOS: Native
-Desktop
+iOS: mWeb Safari
-iOS
+MacOS: Chrome / Safari
-Android
+MacOS: Desktop
diff --git a/contributingGuides/data_flow.png b/contributingGuides/data_flow.png
index e874afce6537..6ee8a4deec5a 100644
Binary files a/contributingGuides/data_flow.png and b/contributingGuides/data_flow.png differ
diff --git a/desktop/electron.png b/desktop/electron.png
index e80796026c67..914e4ff34637 100644
Binary files a/desktop/electron.png and b/desktop/electron.png differ
diff --git a/desktop/icon-adhoc.png b/desktop/icon-adhoc.png
index 5812ad6c5404..8e74a974198f 100644
Binary files a/desktop/icon-adhoc.png and b/desktop/icon-adhoc.png differ
diff --git a/desktop/icon-dev.png b/desktop/icon-dev.png
index 4589faa80d41..2d38819c450b 100644
Binary files a/desktop/icon-dev.png and b/desktop/icon-dev.png differ
diff --git a/desktop/icon-stg.png b/desktop/icon-stg.png
index c605f8aea6ad..fcca93d0cf43 100644
Binary files a/desktop/icon-stg.png and b/desktop/icon-stg.png differ
diff --git a/desktop/icon.png b/desktop/icon.png
index f837c238d19d..f90a81e86c65 100644
Binary files a/desktop/icon.png and b/desktop/icon.png differ
diff --git a/desktop/package-lock.json b/desktop/package-lock.json
index abc1299154ef..0ff280c4b9c6 100644
--- a/desktop/package-lock.json
+++ b/desktop/package-lock.json
@@ -10,15 +10,10 @@
"electron-context-menu": "^2.3.0",
"electron-log": "^4.4.7",
"electron-serve": "^1.0.0",
- "electron-updater": "^4.3.4",
+ "electron-updater": "^6.1.4",
"node-machine-id": "^1.1.12"
}
},
- "node_modules/@types/semver": {
- "version": "7.3.9",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
- "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ=="
- },
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -55,11 +50,11 @@
}
},
"node_modules/builder-util-runtime": {
- "version": "8.9.2",
- "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.9.2.tgz",
- "integrity": "sha512-rhuKm5vh7E0aAmT6i8aoSfEjxzdYEFX7zDApK+eNgOhjofnWb74d9SRJv0H/8nsgOkos0TZ4zxW0P8J4N7xQ2A==",
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.1.tgz",
+ "integrity": "sha512-2rLv/uQD2x+dJ0J3xtsmI12AlRyk7p45TEbE/6o/fbb633e/S3pPgm+ct+JHsoY7r39dKHnGEFk/AASRFdnXmA==",
"dependencies": {
- "debug": "^4.3.2",
+ "debug": "^4.3.4",
"sax": "^1.2.4"
},
"engines": {
@@ -98,9 +93,9 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/debug": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
- "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dependencies": {
"ms": "2.1.2"
},
@@ -155,18 +150,18 @@
"integrity": "sha512-tQJBCbXKoKCfkBC143QCqnEtT1s8dNE2V+b/82NF6lxnGO/2Q3a3GSLHtKl3iEDQgdzTf9pH7p418xq2rXbz1Q=="
},
"node_modules/electron-updater": {
- "version": "4.6.5",
- "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.6.5.tgz",
- "integrity": "sha512-kdTly8O9mSZfm9fslc1mnCY+mYOeaYRy7ERa2Fed240u01BKll3aiupzkd07qKw69KvhBSzuHroIW3mF0D8DWA==",
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.4.tgz",
+ "integrity": "sha512-yYAJc6RQjjV4WtInZVn+ZcLyXRhbVXoomKEfUUwDqIk5s2wxzLhWaor7lrNgxODyODhipjg4SVPMhJHi5EnsCA==",
"dependencies": {
- "@types/semver": "^7.3.6",
- "builder-util-runtime": "8.9.2",
- "fs-extra": "^10.0.0",
+ "builder-util-runtime": "9.2.1",
+ "fs-extra": "^10.1.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
"lodash.escaperegexp": "^4.1.2",
"lodash.isequal": "^4.5.0",
- "semver": "^7.3.5"
+ "semver": "^7.3.8",
+ "tiny-typed-emitter": "^2.1.0"
}
},
"node_modules/emoji-regex": {
@@ -206,9 +201,9 @@
}
},
"node_modules/fs-extra": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
- "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -219,9 +214,9 @@
}
},
"node_modules/graceful-fs": {
- "version": "4.2.9",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
- "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
@@ -333,14 +328,14 @@
}
},
"node_modules/sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
+ "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
},
"node_modules/semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -410,6 +405,11 @@
"node": ">=8"
}
},
+ "node_modules/tiny-typed-emitter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
+ "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="
+ },
"node_modules/universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
@@ -437,11 +437,6 @@
}
},
"dependencies": {
- "@types/semver": {
- "version": "7.3.9",
- "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
- "integrity": "sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ=="
- },
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
@@ -466,11 +461,11 @@
"integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="
},
"builder-util-runtime": {
- "version": "8.9.2",
- "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.9.2.tgz",
- "integrity": "sha512-rhuKm5vh7E0aAmT6i8aoSfEjxzdYEFX7zDApK+eNgOhjofnWb74d9SRJv0H/8nsgOkos0TZ4zxW0P8J4N7xQ2A==",
+ "version": "9.2.1",
+ "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.1.tgz",
+ "integrity": "sha512-2rLv/uQD2x+dJ0J3xtsmI12AlRyk7p45TEbE/6o/fbb633e/S3pPgm+ct+JHsoY7r39dKHnGEFk/AASRFdnXmA==",
"requires": {
- "debug": "^4.3.2",
+ "debug": "^4.3.4",
"sax": "^1.2.4"
}
},
@@ -497,9 +492,9 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"debug": {
- "version": "4.3.3",
- "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
- "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+ "version": "4.3.4",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+ "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
@@ -540,18 +535,18 @@
"integrity": "sha512-tQJBCbXKoKCfkBC143QCqnEtT1s8dNE2V+b/82NF6lxnGO/2Q3a3GSLHtKl3iEDQgdzTf9pH7p418xq2rXbz1Q=="
},
"electron-updater": {
- "version": "4.6.5",
- "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-4.6.5.tgz",
- "integrity": "sha512-kdTly8O9mSZfm9fslc1mnCY+mYOeaYRy7ERa2Fed240u01BKll3aiupzkd07qKw69KvhBSzuHroIW3mF0D8DWA==",
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/electron-updater/-/electron-updater-6.1.4.tgz",
+ "integrity": "sha512-yYAJc6RQjjV4WtInZVn+ZcLyXRhbVXoomKEfUUwDqIk5s2wxzLhWaor7lrNgxODyODhipjg4SVPMhJHi5EnsCA==",
"requires": {
- "@types/semver": "^7.3.6",
- "builder-util-runtime": "8.9.2",
- "fs-extra": "^10.0.0",
+ "builder-util-runtime": "9.2.1",
+ "fs-extra": "^10.1.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
"lodash.escaperegexp": "^4.1.2",
"lodash.isequal": "^4.5.0",
- "semver": "^7.3.5"
+ "semver": "^7.3.8",
+ "tiny-typed-emitter": "^2.1.0"
}
},
"emoji-regex": {
@@ -582,9 +577,9 @@
}
},
"fs-extra": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
- "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -592,9 +587,9 @@
}
},
"graceful-fs": {
- "version": "4.2.9",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz",
- "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
},
"is-fullwidth-code-point": {
"version": "3.0.0",
@@ -680,14 +675,14 @@
}
},
"sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
+ "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
},
"semver": {
- "version": "7.3.5",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
- "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
+ "version": "7.5.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
+ "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"requires": {
"lru-cache": "^6.0.0"
}
@@ -736,6 +731,11 @@
"ansi-regex": "^5.0.1"
}
},
+ "tiny-typed-emitter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz",
+ "integrity": "sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA=="
+ },
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
diff --git a/desktop/package.json b/desktop/package.json
index 45283a260970..bf49d93f1a7b 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -7,7 +7,7 @@
"electron-context-menu": "^2.3.0",
"electron-log": "^4.4.7",
"electron-serve": "^1.0.0",
- "electron-updater": "^4.3.4",
+ "electron-updater": "^6.1.4",
"node-machine-id": "^1.1.12"
},
"author": "Expensify, Inc.",
diff --git a/docs/_sass/_main.scss b/docs/_sass/_main.scss
index c887849ffd99..825b681c8871 100644
--- a/docs/_sass/_main.scss
+++ b/docs/_sass/_main.scss
@@ -350,7 +350,7 @@ button {
img {
display: block;
margin: 20px auto;
- border-radius: 10px;
+ border-radius: 16px;
@include maxBreakpoint($breakpoint-tablet) {
width: 100%;
@@ -546,7 +546,7 @@ button {
align-items: center;
img {
- border-radius: 12px;
+ border-radius: 16px;
width: 100%;
}
}
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md
index 375b00d62eac..2fbdac02e85c 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Business-Bank-Accounts-USD.md
@@ -1,5 +1,159 @@
---
title: Business Bank Accounts - USD
-description: Business Bank Accounts - USD
+description: How to add/remove Business Bank Accounts (US)
---
-## Resource Coming Soon!
+# Overview
+Adding a verified business bank account unlocks a myriad of features and automation in Expensify.
+Once you connect your business bank account, you can:
+- Pay employee expense reports via direct deposit (US)
+- Settle company bills via direct transfer
+- Accept invoice payments through direct transfer
+- Access the Expensify Card
+
+# How to add a verified business bank account
+To connect a business bank account to Expensify, follow the below steps:
+1. Go to **Settings > Account > Payments**
+2. Click **Add Verified Bank Account**
+3. Click **Log into your bank**
+4. Click **Continue**
+5. When you hit the **Plaid** screen, you'll be shown a list of compatible banks that offer direct online login access
+6. Login to the business bank account
+- If the bank is not listed, click the X to go back to the connection type
+- Here you’ll see the option to **Connect Manually**
+- Enter your account and routing numbers
+7. Enter your bank login credentials.
+- If your bank requires additional security measures, you will be directed to obtain and enter a security code
+- If you have more than one account available to choose from, you will be directed to choose the desired account
+Next, to verify the bank account, you’ll enter some details about the business as well as some personal information.
+
+## Enter company information
+This is where you’ll add the legal business name as well as several other company details.
+
+### Company address
+The company address must:
+- Be located in the US
+- Be a physical location
+If you input a maildrop address (PO box, UPS Store, etc.), the address will likely be flagged for review and adding the bank account to Expensify will be delayed.
+
+### Tax Identification Number
+This is the identification number that was assigned to the business by the IRS.
+### Company website
+A company website is required to use most of Expensify’s payment features. When adding the website of the business, format it as, https://www.domain.com.
+### Industry Classification Code
+You can locate a list of Industry Classification Codes here.
+## Enter personal information
+Whoever is connecting the bank account to Expensify, must enter their details under the Requestor Information section:
+- The address must be a physical address
+- The address must be located in the US
+- The SSN must be US-issued
+This does not need to be a signor on the bank account. If someone other than the Expensify account holder enters their personal information in this section, the details will be flagged for review and adding the bank account to Expensify will be delayed.
+
+## Upload ID
+After entering your personal details, you’ll be prompted to click a link or scan a QR code so that you can do the following:
+1. Upload the front and back of your ID
+2. Use your device to take a selfie and record a short video of yourself
+It’s required that your ID is:
+- Issued in the US
+- Unexpired
+
+## Additional Information
+Check the appropriate box under **Additional Information**, accept the agreement terms, and verify that all of the information is true and accurate:
+- A Beneficial Owner refers to an **individual** who owns 25% or more of the business.
+- If you or another **individual** owns 25% or more of the business, please check the appropriate box
+- If someone else owns 25% or more of the business, you will be prompted to provide their personal information
+If no individual owns more than 25% of the company you do not need to list any beneficial owners. In that case, be sure to leave both boxes unchecked under the Beneficial Owner Additional Information section.
+
+# How to validate the bank account
+The account you set up can be found under **Settings > Account > Payment > Bank Accounts** section in either **Verifying** or **Pending** status.
+If it is **Verifying**, then this means we sent you a message and need more information from you. Please check your Concierge chat which should include a message with specific details about what we require to move forward.
+If it is **Pending**, then in 1-2 business days Expensify will administer 3 test transactions to your bank account. Please check your Concierge chat for further instructions. If you do not see these test transactions
+After these transactions (2 withdrawals and 1 deposit) have been processed in your account, visit your Expensify Inbox, where you'll see a prompt to input the transaction amounts.
+Once you've finished these steps, your business bank account is ready to use in Expensify!
+
+# How to share a verified bank account
+Only admins with access to the verified bank account can reimburse employees or pay vendor bills. To grant another admin access to the bank account in Expensify, go to **Settings > Account > Payments > Bank Accounts** and click **"Share"**. Enter their email address, and they will receive instructions from us. Please note, they must be a policy admin on a policy you also have access to in order to share the bank account with them.
+When a bank account is shared, it must be revalidated with three new microtransactions to ensure the shared admin has access. This process takes 1-2 business days. Once received, the shared admin can enter the transactions via their Expensify account's Inbox tab.
+
+Note: A report is shared with all individuals with access to the same business bank account in Expensify for audit purposes.
+
+
+# How to remove access to a verified bank account
+This step is important when accountants and staff leave your business.
+To remove an admin's access to a shared bank account, go to **Settings > Account > Payments > Shared Business Bank Accounts**.
+You'll find a list of individuals who have access to the bank account. Next to each user, you'll see the option to Unshare the bank account.
+
+# How to delete a verified bank account
+If you need to delete a bank account from Expensify, run through the following steps:
+1. Head to **Settings > Account > Payments**
+2. Click the red **Delete** button under the corresponding bank account
+
+Be cautious, as if it hasn't been shared with someone else, the next user will need to set it up from the beginning.
+
+If the bank account is set as the settlement account for your Expensify Cards, you’ll need to designate another bank account as your settlement account under **Settings > Domains > Company Cards > Settings** before this account can be deleted.
+
+# Deep Dive
+
+## Verified bank account requirements
+
+To add a business bank account to issue reimbursements via ACH (US), to pay invoices (US) or utilize the Expensify Card:
+- You must enter a physical address for yourself, any Beneficial Owner (if one exists), and the business associated with the bank account. We **cannot** accept a PO Box or MailDrop location.
+- If you are adding the bank account to Expensify, you must add it from **your** Expensify account settings.
+- If you are adding a bank account to Expensify, we are required by law to verify your identity. Part of this process requires you to verify a US issued photo ID. For utilizing features related to US ACH, your idea must be issued by the United States. You and any Beneficial Owner (if one exists), must also have a US address
+- You must have a valid website for your business to utilize the Expensify Card, or to pay invoices with Expensify.
+
+## Locked bank account
+When you reimburse a report, you authorize Expensify to withdraw the funds from your account. If your bank rejects Expensify’s withdrawal request, your verified bank account is locked until the issue is resolved.
+
+Withdrawal requests can be rejected due to insufficient funds, or if the bank account has not been enabled for direct debit.
+If you need to enable direct debits from your verified bank account, your bank will require the following details:
+- The ACH CompanyIDs (1270239450 and 4270239450)
+- The ACH Originator Name (Expensify)
+To request to unlock the bank account, click **Fix** on your bank account under **Settings > Account > Payments > Bank Accounts**.
+This sends a request to our support team to review exactly why the bank account was locked.
+Please note, unlocking a bank account can take 4-5 business days to process.
+
+## Error adding ID to Onfido
+Expensify is required by both our sponsor bank and federal law to verify the identity of the individual that is initiating the movement of money. We use Onfido to confirm that the person adding a payment method is genuine and not impersonating someone else.
+
+If you get a generic error message that indicates, "Something's gone wrong", please go through the following steps:
+
+1. Ensure you are using either Safari (on iPhone) or Chrome (on Android) as your web browser.
+2. Check your browser's permissions to make sure that the camera and microphone settings are set to "Allow"
+3. Clear your web cache for Safari (on iPhone) or Chrome (on Android).
+4. If using a corporate Wi-Fi network, confirm that your corporate firewall isn't blocking the website.
+5. Make sure no other apps are overlapping your screen, such as the Facebook Messenger bubble, while recording the video.
+6. On iPhone, if using iOS version 15 or later, disable the Hide IP address feature in Safari.
+7. If possible, try these steps on another device
+8. If you have another phone available, try to follow these steps on that device
+If the issue persists, please contact your Account Manager or Concierge for further troubleshooting assistance.
+
+# FAQ
+## What is a Beneficial Owner?
+
+A Beneficial Owner refers to an **individual** who owns 25% or more of the business. If no individual owns 25% or more of the business, the company does not have a Beneficial Owner.
+
+
+## What do I do if the Beneficial Owner section only asks for personal details, but our business is owned by another company?
+
+
+Please only indicate you have a Beneficial Owner, if it is an individual that owns 25% or more of the business.
+
+## Why can’t I input my address or upload my ID?
+
+
+Are you entering a US address? When adding a verified business bank account in Expensify, the individual adding the account, and any beneficial owner (if one exists) are required to have a US address, US photo ID, and a US SSN. If you do not meet these requirements, you’ll need to have another admin add the bank account, and then share access with you once verified.
+
+
+## Why am I being asked for documentation when adding my bank account?
+When a bank account is added to Expensify, we complete a series of checks to verify the information provided to us. We conduct these checks to comply with both our sponsor bank's requirements and federal government regulations, specifically the Bank Secrecy Act / Anti-Money Laundering (BSA / AML) laws. Expensify also has anti-fraud measures in place.
+If automatic verification fails, we may request manual verification, which could involve documents such as address verification for your business, a letter from your bank confirming bank account ownership, etc.
+
+If you have any questions regarding the documentation request you received, please contact Concierge and they will be happy to assist.
+
+
+## I don’t see all three microtransactions I need to validate my bank account. What should I do?
+
+It's a good idea to wait till the end of that second business day. If you still don’t see them, please reach out to your bank and ask them to whitelist our ACH ID's **1270239450** and **4270239450**. Expensify’s ACH Originator Name is "Expensify".
+
+Make sure to reach out to your Account Manager or to Concierge once you have done so and our team will be able to re-trigger those 3 transactions!
+
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md
index f1d939ca9c89..8b6ea7de2642 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Direct-Bank-Connections.md
@@ -1,5 +1,108 @@
---
title: Direct Bank Connections
-description: Direct Bank Connections
+description: Connect your company cards in Expensify to bring all team members’ card expenses into their accounts and conveniently manage card transactions and out-of-pocket expenses in one place.
+
---
-## Resource Coming Soon!
+# Overview
+If you're a Domain Admin, you have the power to connect and manage your company cards in Expensify centrally. If your company uses a card program with one of our Approved! Banking Partners, you can easily connect the card feed to Expensify via login credentials. Connecting company cards is a great way to bring all team members’ card expenses into their accounts and conveniently manage card transactions and out-of-pocket expenses in one place. Keeping things organized has never been easier!
+# How to connect company cards using a direct bank connection
+1. Go to **Settings > Domains > _Domain Name_ > Company Cards**
+2. Click **Import Card**
+
+![Expensify domain cards](https://help.expensify.com/assets/images/ExpensifyHelp_DomainCards.png){:width="100%"}
+
+3. Select your card issuer and input the **master administrative login credentials**
+4. You will then be able to assign accounts to cardholders
+5. Set a start date from which expenses will appear in their accounts
+## How to assign company cards
+After connecting your company cards with Expensify, you can assign each card to its respective cardholder.
+To assign the company cards, go to **Settings > Domains > _Domain Name_ > Company Cards**.
+If you have more than one card feed, select the correct feed in the drop-down list in the Company Card section.
+
+![Expensify domain card list](https://help.expensify.com/assets/images/ExpensifyHelp_DomainCardsList.png){:width="100%"}
+
+
+Once you’ve selected the appropriate feed, click the `Assign New Cards` button to populate the emails and the last four digits of the cardholder.
+
+![Expensify assign cards](https://help.expensify.com/assets/images/ExpensifyHelp_AssignCardBtn.png){:width="100%"}
+
+![Expensify domain assign card form](https://help.expensify.com/assets/images/ExpensifyHelp_AssignCardForm.png){:width="100%"}
+
+ **Select the cardholder:** Search the populated list for all employee email addresses. The employee will need to have an email address under this Domain to assign a card.
+
+**Select the card:** Search the list using the last four digits of the card number. If no transactions have been posted on the card, the card number will not appear in the list. You can instead assign the card by typing in the full card number in the field.
+
+**Note:** If you're assigning a card by typing in the full PAN (the full card number), press the ENTER key on your keyboard after typing the full PAN into the card field. The field may clear itself after pressing ENTER, but click **Assign** anyway and then verify that the assignment shows up in the cardholder table.
+
+**Set the transaction start date (optional):** Any transactions that were posted before this date will not be imported into Expensify. If you do not make a selection, it will default to the earliest available transactions from the card.
+Please note we can only import data for the time period the bank is releasing to us. Most banks only provide a certain amount of historical data, averaging 30-90 days into the past. It's not possible to override the start date the bank has provided via this tool.
+
+**Click the Assign button:** Once assigned, you will see each cardholder associated with their card and the start date listed.
+
+![Expensify domain assigned cards](https://help.expensify.com/assets/images/ExpensifyHelp_AssignedCard.png){:width="100%"}
+
+
+## How to unassign company cards
+_**Important** - Before you begin the unassigning process, please note that unassigning a company card will **delete** any **Open** or **Unreported** expenses in the cardholder's account. To avoid this, users should submit these expenses **before** their cards are unassigned._
+
+If you need to unassign a certain card, click the **Actions** button associated with the card in question and then click **Unassign**.
+
+![Expensify domain unassign cards](https://help.expensify.com/assets/images/ExpensifyHelp_UnassignCard.png){:width="100%"}
+
+To completely remove the card connection, unassign every card from the list and then refresh the page.
+
+**Note:** If expenses are **Processing** and then rejected, they will also be deleted when they're returned to an **Open** state as the linked card they're linked to no longer exists.
+
+# Deep Dive
+## Configure card settings
+Once you’ve imported your company cards, the next step is configuring the cards’ settings.
+If you're using a connected accounting system such as NetSuite, Xero, Sage Intacct, Quickbooks Desktop, or QuickBooks Online. In that case, you can connect the card to export to a specific credit card GL account.
+1. Go to **Settings > Domains > _Domain Name_ > Company Cards**
+2. Click **Edit Exports** on the right-hand side of the card table and select the GL account you want to export expenses to
+3. You're all done. After the account is set, exported expenses will be mapped to the specific account selected when exported by a Domain Admin.
+
+![Expensify domain cards settings](https://help.expensify.com/assets/images/ExpensifyHelp_UnassignCard-1.png){:width="100%"}
+
+
+You can access the remaining company card settings by navigating to **Settings > Domains > _Domain Name_ > Company Cards > Settings.** More information on card settings can be found by searching **“How to configure company card settings”**.
+
+# FAQ
+## How can I connect and manage my company’s cards centrally if I’m not a domain admin?
+ If you cannot access Domains, you must request Domain Admin access to an existing Domain Admin (usually the workspace owner).
+
+## Are direct bank connections the best option for connecting credit cards to Expensify?
+If we currently have a connection with your bank, then it’s a good option. However, if you want enhanced stability and additional functionality, consider opting for a commercial card feed directly from your bank or getting the Expensify card.
+
+## My card feed is set up. Why is a specific card not coming up when I try to assign it to an employee?
+Cards will appear in the drop-down when activated and have at least one posted transaction. If the card is activated and has been used for a while and you're still not seeing it, please contact your Account Manager or message Concierge for further assistance.
+
+## Is there a fee for utilizing direct card connections?
+Nope! Direct card connections come at no extra cost and are part of the Corporate Workspace pricing.
+
+## What is the difference between commercial card feeds and direct bank connections?
+The direct bank connection is a connection set up with your login credentials for that account. In contrast, the commercial card feed is set up by your bank requesting that Visa/MasterCard/Amex send a daily transaction feed to Expensify. The former can be done without the assistance of your bank or Expensify, but the latter is more stable and reliable.
+
+## What if my bank uses a card program that isn't with one of Expensify's Approved! Banking partners?
+If your company uses a Commercial Card program that isn’t with one of our Approved! Banking Partners (which supports connecting the feed via login credentials), the best way to import your company cards is by setting up a direct Commercial Card feed between Expensify and your bank. Note the Approved! Banking Partners include:
+- Bank of America
+- Citibank
+- Capital One
+- Chase
+- Wells Fargo
+- Amex
+- Stripe
+- Brex
+
+## Why do direct bank connections break?
+Banks often make changes to safeguard your confidential information, and when they do, we need to update the connection between Expensify and the bank. We have a team of engineers who work closely with banks to monitor this and update our software accordingly when this happens.
+
+## How do I resolve errors while trying to import my card?
+Ensure you're importing your card in the correct spot in Expensify and selecting the proper bank connection. For company cards, use the master administrative credentials to import your set of cards at **Settings > Domains > _Domain Name_ > Company Cards > Import Card.**
+
+## Why is my card connection broken after working fine?
+The first step is to check for any changes to your bank information. Have you recently changed your banking password without updating it in Expensify? Has your banking username or card number been updated? Did you edit your security questions for your bank? Additionally, if your security questions have changed or their answers aren't saved in Expensify. In that case, we won't be able to access your account list, and you'll need to address this within Expensify.
+
+If you've answered "yes" to any of these questions, you'll need to update this information in Expensify and manually re-establish the connection. Please note that Expensify cannot automatically update this information for you.
+A Domain Admin can fix the connection by heading to **Settings > Domains > _Domain Name_ > Company Cards > Fix**. You will be prompted to enter the new credentials/updated information, and this should reestablish the connection.
+If you are still experiencing issues with the card connection, please search for company card troubleshooting or contact Expensify Support for help.
+
diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md
index e3d1307e6a05..8d1a79e49eaf 100644
--- a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md
+++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Troubleshooting.md
@@ -1,5 +1,101 @@
---
title: Troubleshooting
-description: Troubleshooting
+description: How to troubleshoot company card importing in Expensify
---
-## Resource Coming Soon!
+# Overview
+Whether you're encountering issues related to company cards, require assistance with company card account access, or have questions about company card import features, you've come to the right place.
+
+## How to add company cards to Expensify
+You can add company credit cards under the Domain settings in your Expensify account by navigating to *Settings* > *Domain* > _Domain Name_ > *Company Cards* and clicking *Import Card/Bank* and following the prompts.
+
+# Errors connecting company cards
+
+## Error: Too many attempts
+If you've been locked out while trying to import a new card, you'll need to wait a full 24 hours before trying again. This lock happens when incorrect online banking credentials are entered multiple times, and it's there for your security — it can't be removed. To avoid this, make sure your online banking credentials are correct before attempting to import your card again.
+
+## Error: Invalid credentials/Login failed
+Verify your ability to log into your online banking portal by attempting to log into your bank account via the banking website.
+Check for any potential temporary outages on your bank's end that may affect third-party connections like Expensify.
+For specific card types:
+- *Chase Card*: Confirm your password meets their new 8-32 character requirement.
+- *Wells Fargo Card*: Ensure your password is under 14 characters. Reset it if necessary before importing your card to Expensify. If your card is already imported, update it and use the "Fix Card" option to reestablish the connection.
+- *SVB Card*: Enable Direct Connect from the SVB website and use your online banking username and Direct Connect PIN instead of your password when connecting an SVB card. If connecting via *Settings* > *Domain* > _[Domain Name]_ > *Company Cards*, contact SVB for CDF feed setup.
+
+## Error: Direct Connect not enabled
+Direct Connect will need to be enabled in your account for your bank/credit card provider before you can import your card to Expensify. Please reach out to your bank to confirm if this option is available for your account, as well as get instructions on how to get this setup.
+
+## Error: Account Setup
+This error message typically indicates that there's something you need to do on your bank account's end. Please visit your online banking portal and check if there are any pending actions required. Once you've addressed those, you can try connecting your card again.
+For Amex cardholders with multiple card programs in your Amex US Business account: To import multiple card programs into Expensify, you'll need to contact Amex and request that they separate the multiple card programs into distinct logins. For instance, you'll want to have your _Business Platinum_ cards under *"username1/password1"* and _Business Gold_ cards under *"username2/password2."* This ensures smooth integration with Expensify.
+
+## Error: Account type not supported
+If Expensify doesn't have a direct connection to your bank/credit card provider, we can still support the connection via spreadsheet import, which you can learn more about [here](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/CSV-Import#gsc.tab=0). If the cards you're trying to import are company cards, it’s possible that you might be able to obtain a commercial feed directly from your bank. Please find more information on this [here](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-credit-cards/company-cards/Commercial-Card-Feeds#gsc.tab=0).
+
+## Error: Username/Password/Questions out of date
+Your company card connection is broken because we're missing some answers to some security questions. Please head to *Settings* > *Domain* > _[Domain Name]_ > *Company Cards* and click _Fix Card_.
+This will require you to answer your bank's security questions. You will need to do this for each security question you have with your bank; so if you have 3 security questions, you will need to do this 3 times.
+
+## Error: Account not found/Card number changed
+This error message appears when you have been issued a new card, or if there's been a significant change to the account in some other way (password and/or card number change).
+When your online bank/card account password has been changed, you may need to update the details on the Expensify end as well. To do this, navigate to *Settings* > *Domain* > _[Domain Name]_ > *Company Cards* and click _Fix Card_.
+If there’s been a recent change to the card number, you’ll have to remove the card with the previous number and re-import the card using the new number. A Domain Admin will have to re-assign the card via *Settings* > *Domain* > _Domain Name_ > *Company Cards*. Before removing the card, please ensure *all Open reports have been submitted*, as removing the card will remove all imported transactions from the account that are associated with that card.
+
+## Error: General connection error
+This error message states that your bank or credit card provider is under maintenance and is unavailable at this time. Try waiting a few hours before trying to import your credit card again. Check out our [status page](https://status.expensify.com/) for updates on bank/credit card connections, or you can also choose to subscribe to updates for your specific account type.
+
+## Error: Not seeing cards listed after a successful login
+The card will only appear in the drop-down list for assignment once it’s activated and there are transactions that have been incurred and posted on the card. If not, the card won't be available to assign to the card holder until then.
+
+# Troubleshooting issues assigning company cards
+
+## Why do bank connections break?
+Banks often make changes to safeguard your confidential information, and when they do, we need to update the connection between Expensify and the bank. We have a team of engineers that works closely with banks to monitor this and update our software accordingly when this happens.
+The first step is to check if there have been any changes to your bank information. Have you recently changed your banking password without updating it in Expensify? Has your banking username or card number been updated? Did you update your security questions for your bank?
+If you've answered "yes" to any of these questions, a Domain Admins need to update this information in Expensify and manually reestablish the connection by heading to *Settings* > *Domains* > _Domain Name_ > *Company Cards* > *Fix*. The Domain Admin will be prompted to enter the new credentials/updated information and this should reestablish the connection.
+
+## How do I resolve errors while I’m trying to import my card?*
+Make sure you're importing your card in the correct spot in Expensify and selecting the right bank connection. For company cards, use the master administrative credentials to import your set of cards at *Settings* > *Domains* > _Domain Name_ > *Company Cards* > *Import Card*.
+Please note there are some things that cannot be bypassed within Expensify, including two-factor authentication being enabled within your bank account. This will prevent the connection from remaining stable and will need to be turned off on the bank side.
+
+## What are the most reliable bank connections in Expensify?*
+The most reliable corporate card to use with Expensify is the Expensify Card. We offer daily settlement, unapproved expense limits, and real-time compliance for secure and efficient spending, as well as 2% cash back. Click here to learn more or apply.
+Additionally, we've teamed up with major banks worldwide to ensure a smooth import of credit card transactions into your accounts. Corporate cards from the following banks also offer the most dependable connections in Expensify:
+- American Express
+- Bank of America
+- Brex
+- Capital One
+- Chase
+- Citibank
+- Stripe
+- Wells Fargo
+
+Commercial feeds for company cards are the dependable connections in Expensify. If you have a corporate or commercial card account, you might have access to a daily transaction feed where expenses from Visa, MasterCard, and American Express are automatically sent to Expensify. Reach out to your banking relationship manager to check if your card program qualifies for this feature.
+
+# Troubleshooting American Express Business
+
+## Amex account roles
+American Express provides three different roles for accessing accounts on their website. When connecting Amex cards to Expensify, it's crucial to use the credentials of the Primary/Basic account holder. Here's what each role means:
+- *Primary/Basic Account Holder*: The person who applied for the American Express Business card, owns the account, manages its finances, and controls card issuance and account management. They can view all charges by other cardmembers on their account. They can see all charges made by other cardmembers on their account.
+- *Supplemental Cardmember (Employee Cardmember)*: Chosen by the Primary Card Member (typically an employee on business accounts), they can access their own card info and make payments but can't see other account details.
+- *Authorized Account Manager (AAM)*: Chosen by the Primary Card Member, AAMs can manage the account online or by phone, but they can't link cards to services like Expensify. They have admin rights, including adding cards, making payments, canceling cards, and setting limits. To connect cards to Expensify, use the Primary Card Holder's credentials for full access.
+
+## The connection is established but there are no cards to assign
+
+When establishing the connection, you must assign cards during the same session. It isn't possible to create the connection, log out, and assign the cards later, as the connection will not stick, and require you to reattempt the connection again.
+
+## Amex error: Card isn't eligible
+This error comes directly from American Express and is typically related to an account that is not a business account or using credentials that are not the primary account holder credentials.
+
+## Amex error: Session has expired
+If you get an error stating an American Express Business Card “Your session has expired. Please return to Expensify and try again, this always means that you are using the incorrect credentials. Remember, you need to use primary/basic cardholder credentials. If you are not sure which credentials you should use, reach out to American Express for guidance.
+
+## Connect multiple company card programs under the same credentials
+If you have multiple company card programs with the same credentials, you can select ALL programs at once. With this, all programs will be under one dropdown. Make sure to select all cards each time you are adding any cards from any program.
+If you would like your card programs listed under separate dropdowns, you can select only that group making sure to select all cards from that group each time you are adding a new card.
+Once you have authorized the account, you’ll be guided back to Expensify where you’ll assign all necessary cards across all programs.
+This will store all cards under the same American Express Business connection dropdown and allow all cards to be added to Expensify for you to assign to users.
+*Important Reminder*: Whenever you need to access the connection to assign a new card, you must still choose "ALL card programs." For instance, if you have a new employee with a card under your Business Gold Rewards Card program, you'll still need to authorize all the cards in that program or all the programs if you have only one dropdown menu!
+
+## Add cards under different programs with different logins
+If you have multiple card programs with different credentials, you will need to have another Domain Admin account add each card program from their own account.
+Once all Domain Admins have connected and assigned the cards that they are the Primary account holder for, all cards will be listed under one *American Express (New and Upgraded)* list in the Domain Company Card page.
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md b/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md
index 963186916f01..b835db54cbf2 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Overview.md
@@ -1,5 +1,38 @@
---
-title: Overview
-description: Overview
+title: Billing in Expensify
+description: An overview of how billing works in Expensify.
---
-## Resource Coming Soon!
+# Overview
+Expensify’s billing is based on monthly member activity. At the beginning of each month, you’ll be billed for the previous month’s activity. Your Expensify bill ultimately depends on your plan type, whether you're on an annual subscription or pay-per-use billing, and whether you’re using Expensify Cards.
+# How billing works in Expensify
+Expensify bills the owners of Group Workspaces on the first of each month for the previous month's usage. You can find billing receipts in **Settings > Account > Payments > Billing History**. We recommend that businesses have one billing owner for all of their Group Workspaces.
+## Active members
+An **active member** is anyone who chats, creates, submits, approves, reimburses, or exports a report in Expensify in any given month. This includes Copilots and automated settings.
+## Annual subscription
+With an annual subscription, you set your monthly active member count at the beginning and get a 50% discount on your monthly active member cost. That means an annual subscription paired with the Collect plan will cost $10 per monthly active member instead of $20, and the Control plan will cost $18 instead of $36.
+
+Each month, you’ll be billed for the amount of members you originally set in your subscription size. Any active members in a given month above this subscription size will be billed at the pay-per-use rate.
+
+For example, let’s say you set your annual subscription size at 10 members and you’re on the Control plan. You’ll be billed $18/member for 10 members each month. However, let’s say in one particular month you had 12 active members, you’d be billed at $18/member for the 10 members in your subscription size + $36/member (pay-per-use rate) for the additional 2 active members.
+
+You can always increase your annual subscription size, which will extend your annual subscription length. You cannot reduce your annual subscription size until your current subscription has ended. If you have any questions about this, reach out to Concierge or your account manager.
+## Pay-per-use
+The pay-per-use rate is the full rate per active member without any discounts. The pay-per-use rate for each member on the Collect plan is $20 and on the Control plan is $36.
+## How the Expensify Card can reduce your bill
+Bundling the Expensify Card with an annual subscription ensures you pay the lowest possible monthly price for Expensify. And the more you spend on Expensify Cards, the lower your bill will be.
+
+If at least 50% of your approved USD spend in a given month is on your company’s Expensify Cards, you will receive an additional 50% discount on the price per member. This additional 50% discount, when coupled with an annual subscription, brings the price per member to $5 on a Collect plan and $9 on a Control plan.
+
+Additionally, every month, you receive 1% cash back on all Expensify Card purchases, and 2% if the spend across your Expensify Cards is $250k or more. Any cash back from the Expensify Card is first applied to your Expensify bill, further reducing your price per member. Any leftover cash back is deposited directly into your connected bank account.
+## Savings calculator
+To see how much money you can save (and even earn!) by using the Expensify Card, check out our [savings calculator](https://use.expensify.com/price-savings-calculator). Just enter a few details and see how much you’ll save!
+# FAQ
+## What if we put less than 50% of our total spend on the Expensify Card?
+If you put less than 50% of your total USD spend on your Expensify Card, your bill gets discounted on a sliding scale based on the percentage of use. So if you don't use the Expensify Card at all, you'll be charged the full rate for each member based on your plan and subscription.
+Example:
+- Annual subscription discount: 50%
+- % of Expensify Card spend (USD) across all workspaces: 20%
+- Expensify Card discount: 20%
+You save 70% on the price per member on your bill for that month.
+
+Note: USD spend refers to approved USD transactions on the Expensify Card in any given month, compared to all approved USD spend on workspaces in that same month.
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Receipt-Breakdown.md b/docs/articles/expensify-classic/billing-and-subscriptions/Receipt-Breakdown.md
new file mode 100644
index 000000000000..275fb2c93cf0
--- /dev/null
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Receipt-Breakdown.md
@@ -0,0 +1,49 @@
+---
+title: Receipts Breakdown
+description: This article goes over the Expensify receipt for billing owners.
+---
+
+# Overview
+This article will give you (the billing owner) a detailed breakdown of your Expensify bill.
+
+Your receipt is broken up into multiple sections that include:
+1. A high-level summary of your total Expensify bill
+2. Ways to reduce your bill and get paid to use Expensify
+3. A billing breakdown that covers all activity and discounts
+4. An activity breakdown by workspace
+
+## How-to understand the high-level summary
+The top section will show the total amount you paid as the billing owner of Expensify workspaces and give you a breakdown of price per member. Every member of your workspace(s) gets to store data, review data, and access free features like Expensify Chat. Thus, we show the total price and then use all of the members across all of the workspaces you own to calculate the price per member. Further down in the receipt, and in this article, we break down the members who generated billable activity.
+
+## How-to reduce your bill and get paid to use Expensify
+Chances are you can actually get paid to use Expensify with the Expensify Card. In this section of the receipt, we outline how much money you're leaving on the table by not using the Expensify Card. You can click `Get started` to connect with your account manager (if you have one) or Concierge, both of whom can help get you started with the card.
+
+_Note: Currently, we offer Expensify Cards to companies with USD bank accounts._
+
+## How-to understand your billing breakdown
+Your receipt will have a detailed breakdown of activity and discounts across all workspaces. Here's a description of items that may appear on your bill:
+- [Number of] Inactive workspace members @ $0.00
+ - All inactive members from any of your workspaces.
+- [Number of] Chat-only members @ $0.00
+ - Any workspace members who chatted but didn't generate any other billable activity. Learn more about [chatting for free.](https://help.expensify.com/articles/new-expensify/getting-started/chat/Everything-About-Chat#gsc.tab=0)
+- [Number of] Annual Control members @ $18.00
+ - Any members included in your annual subscription on the Control plan.
+- [Number of] Pay-per-use Control members @ $36.00
+ - Any members above your annual subscription size on the Control plan. They're billed at the pay-per-use rate.
+- [Number of] Annual Collect members @ $10.00
+ - Any members included in your annual subscription on the Collect plan.
+- [Number of] Pay-per-use Collect members @ $20.00
+ - Any members above your annual subscription size on the Collect plan. These members are billed at the pay-per-use rate.
+- [Number of] Free members @ $0.00
+ - All members across any of your Free workspaces.
+- X% Expensify Card discount with $Y spend
+ - This shows the % discount you're getting based on total spend across your Expensify Cards. This is only available in the US.
+- X% Expensify Card cash back credit for $Y spend
+ - The amount of cash back you've earned based on total spend across your Expensify Cards. This is only available in the US.
+- 50% ExpensifyApproved! partner discount
+ - If you're part of an accounting firm, you get an additional discount for being our partner. [Learn more about our ExpensifyApproved! accountants program.](https://use.expensify.com/accountants-program)
+- Total
+ - Sum of all the line items above.
+
+## How-to understand your activity breakdown
+This section will list all of your workspaces alongside their IDs and break down the billing for each of them.
diff --git a/docs/articles/expensify-classic/expense-and-report-features/Currency.md b/docs/articles/expensify-classic/expense-and-report-features/Currency.md
index e5c9096fa610..eb6ca9bb2d40 100644
--- a/docs/articles/expensify-classic/expense-and-report-features/Currency.md
+++ b/docs/articles/expensify-classic/expense-and-report-features/Currency.md
@@ -1,5 +1,64 @@
---
-title: Currency
-description: Currency
+title: Report Currency
+description: Understanding expense and report currency
---
-## Resource Coming Soon!
+
+# Overview
+As a workspace admin, you can choose a default currency for your employees' expense reports, and we’ll automatically convert any expenses into that currency.
+
+Here are a few essential things to remember:
+
+- Currency settings for a workspace apply to all expenses under that workspace. If you need different default currencies for certain employees, creating separate workspaces and configuring the currency settings is best.
+- As an admin, the currency settings you establish in the workspace will take precedence over any currency settings individual users may have in their accounts.
+- Currency is a workspace-level setting, meaning the currency you set will determine the currency for all expenses submitted on that workspace.
+
+# How to select the currency on a workspace
+
+## As an admin on a group workspace
+
+1. Sign into your Expensify web account
+2. Go to **Settings > Workspaces > Group > _[Workspace Name]_> Reports > Report Basics**
+3. Adjust the **Report Output Currency**
+
+## On an individual workspace
+
+1. Sign into your Expensify web account
+2. Go to **Settings > Workspaces > Individual >_[Workspace Name]_> Reports > Report Basics**
+3. Adjust the **Report Output Currency**
+
+Please note the currency setting on an individual workspace is overridden when you submit a report on a group workspace.
+
+# Deep Dive
+
+## Conversion Rates
+
+Using data from Open Exchange Rates, Expensify takes the average rate on the day the expense occurred to convert an expense from one currency to another. The conversion rate can vary depending on when the expense happened since the rate is determined after the market closes on that specific date.
+
+If the markets aren’t open on the day the expense takes place (i.e., on a Saturday), Expensify will use the daily average rate from the last available market day before the purchase took place.
+
+When an expense is logged for a future date, possibly to anticipate a purchase that has yet to occur, we'll use the most recent available data. This means the report's value may change up to the day of that expense.
+
+## Managing expenses for employees in several different countries
+
+Suppose you have employees scattered across the globe who submit expense reports in various currencies. The best way to manage those expenses is to create separate group workspaces for each location or region where your employees are based.
+
+Then, set the default currency for that workspace to match the currency in which the employees are reimbursed.
+
+For example, if you have employees in the US, France, Japan, and India, you’d want to create four separate workspaces, add the employees to each, and then set the corresponding currency for each workspace.
+
+# FAQ
+
+## I have expenses in several different currencies. How will this show up on a report?
+
+If you're traveling to foreign countries during a reporting period and making purchases in various currencies, each expense is imported with the currency of the purchase.
+
+On your expense report, Expensify will automatically convert each expense to the default currency set for the group workspace.
+
+## How does the currency of an expense impact the conversion rate?
+
+Expenses entered in a foreign currency are automatically converted to the default currency on your workspace. The conversion uses the day’s average trading rate pulled from [Open Exchange Rates](https://openexchangerates.org/).
+
+If you want to bypass the exchange rate conversion, you can manually enter an expense in your default currency instead.
+
+
+
diff --git a/docs/articles/expensify-classic/expensify-card/Card-Settings.md b/docs/articles/expensify-classic/expensify-card/Card-Settings.md
index 35708b6fbb1e..a8d56f267757 100644
--- a/docs/articles/expensify-classic/expensify-card/Card-Settings.md
+++ b/docs/articles/expensify-classic/expensify-card/Card-Settings.md
@@ -2,74 +2,76 @@
title: Expensify Card Settings
description: Admin Card Settings and Features
---
-## Expensify Card - admin settings and features
-
+
# Overview
-
+
The Expensify Card offers a range of settings and functionality to customize how admins manage expenses and card usage in Expensify. To start, we'll lay out the best way to make these options work for you.
-
+
Set Smart Limits to control card spend. Smart Limits are spend limits that can be set for individual cards or specific groups. Once a given Smart Limit is reached, the card is temporarily disabled until expenses are approved.
-
+
Monitor spend using your Domain Limit and the Reconciliation Dashboard.
Your Domain Limit is the total Expensify Card limit across your entire organization. No member can spend more than what's available here, no matter what their individual Smart Limit is. A Domain Limit is dynamic and depends on a number of factors, which we'll explain below.
-
+
Decide the settlement model that works best for your business
Monthly settlement is when your Expensify Card balance is paid in full on a certain day each month. Though the Expensify Card is set to settle daily by default, any Domain Admin can change this setting to monthly.
-
+
Now, let's get into the mechanics of each piece mentioned above.
-
+
# How to set Smart Limits
Smart Limits allow you to set a custom spend limit for each Expensify cardholder, or default limits for groups. Setting a Smart Limit is the step that activates an Expensify card for your user (and issues a virtual card for immediate use).
-
+
## Set limits for individual cardholders
As a Domain Admin, you can set or edit Custom Smart Limits for a card by going to Settings > Domains > Domain Name > Company Cards. Simply click Edit Limit to set the limit. This limit will restrict the amount of unapproved (unsubmitted and Processing) expenses that a cardholder can incur. After the limit is reached, the cardholder won't be able to use their card until they submit outstanding expenses and have their card spend approved. If you set the Smart Limit to $0, the user's card can't be used.
## Set default group limits
Domain Admins can set or edit custom Smart Limits for a domain group by going to Settings > Domains > Domain Name > Groups. Just click on the limit in-line for your chosen group and amend the value.
-
+
This limit will apply to all members of the Domain Group who do not have an individual limit set via Settings > Domains > Domain Name > Company Cards.
+
## Refreshing Smart Limits
To let cardholders keep spending, you can approve their pending expenses via the Reconciliation tab. This will free up their limit, allowing them to use their card again.
-
+
To check an unapproved card balance and approve expenses, click on Reconciliation and enter a date range, then click though the Unapproved total to see what needs approving. You can add to a new report or approve an existing report from here.
-
+
You can also increase a Smart Limit at any time by clicking Edit Limit.
-
+
# Understanding your Domain Limit
-
+
To get the most accurate Domain Limit for your company, connect your bank account via Plaid under Settings > Account > Payments > Add Verified Bank Account.
-
+
If your bank isn't supported or you're having connection issues, you can request a custom limit under Settings > Domains > Domain Name > Company Cards > Request Limit Increase. As a note, you'll need to provide three months of unredacted bank statements for review by our risk management team.
-
+
Your Domain Limit may fluctuate from time to time based on various factors, including:
-
+
- Available funds in your Verified Business Bank Account: We regularly check bank balances via Plaid. A sudden drop in balance within the last 24 hours may affect your limit. For 'sweep' accounts, be sure to maintain a substantial balance even if you're sweeping daily.
- Pending expenses: Review the Reconciliation Dashboard to check for large pending expenses that may impact your available balance. Your Domain Limit will adjust automatically to include pending expenses.
- Processing settlements: Settlements need about three business days to process and clear. Several large settlements over consecutive days may impact your Domain Limit, which will dynamically update when settlements have cleared.
-
-As a note, if your Domain Limit is reduced to $0, your cardholders can't make purchases even if they have a larger Smart Limit set on their individual cards.
+
+As a note, if your Domain Limit is reduced to $0, your cardholders can't make purchases even if they have a larger Smart Limit set on their individual cards.
+
# How to reconcile Expensify Cards
## How to reconcile expenses
Reconciling expenses is essential to ensuring your financial records are accurate and up-to-date.
-
+
Follow the steps below to quickly review and reconcile expenses associated with your Expensify Cards:
-
+
1. Go to Settings > Domains > Domain Name > Company Cards > Reconciliation > Expenses
2. Enter your start and end dates, then click Run
3. The Imported Total will show all Expensify Card transactions for the period
4. You'll also see a list of all Expensify Cards, the total spend on each card, and a snapshot of expenses that have and have not been approved (Approved Total and Unapproved Total, respectively)
By clicking on the amounts, you can view the associated expenses
-
+
+
## How to reconcile settlements
A settlement is the payment to Expensify for the purchases made using the Expensify Cards.
-
+
The Expensify Card program can settle on either a daily or monthly basis. One thing to note is that not all transactions in a settlement will be approved when running reconciliation.
-
+
You can view the Expensify Card settlements under Settings > Domains > Domain Name > Company Cards > Reconciliation > Settlements.
-
+
By clicking each settlement amount, you can see the transactions contained in that specific payment amount.
-
+
Follow the below steps to run reconciliation on the Expensify Card settlements:
-
+
1. Log into the Expensify web app
2. Click Settings > Domains > Domain Name > Company Cards > Reconciliation tab > Settlements
3. Use the Search function to generate a statement for the specific period you need
@@ -82,7 +84,7 @@ Follow the below steps to run reconciliation on the Expensify Card settlements:
- Card: refers to the Expensify credit card number and cardholder's email address
- Business Account: the business bank account connected to Expensify that the settlement is paid from
- Transaction ID: a special ID that helps Expensify support locate transactions if there's an issue
-
+
5. Review the individual transactions (debits) and the payments (credits) that settled them
6. Every cardholder will have a virtual and a physical card listed. They're handled the same way for settlements, reconciliation, and exporting.
7. Click Download CSV for reconciliation
@@ -90,77 +92,78 @@ Follow the below steps to run reconciliation on the Expensify Card settlements:
9. To reconcile pre-authorizations, you can use the Transaction ID column in the CSV file to locate the original purchase
10. Review account payments
11. You'll see payments made from the accounts listed under Settings > Account > Payments > Bank Accounts. Payment data won't show for deleted accounts.
-
+
You can use the Reconciliation Dashboard to confirm the status of expenses that are missing from your accounting system. It allows you to view both approved and unapproved expenses within your selected date range that haven't been exported yet.
-
+
+
# Deep dive
## Set a preferred workspace
Some customers choose to split their company card expenses from other expense types for coding purposes. Most commonly this is done by creating a separate workspace for card expenses.
-
+
You can use the preferred workspace feature in conjunction with Scheduled Submit to make sure all newly imported card expenses are automatically added to reports connected to your card-specific workspace.
+
## How to change your settlement account
You can change your settlement account to any other verified business bank account in Expensify. If your bank account is closing, make sure you set up the replacement bank account in Expensify as early as possible.
-
+
To select a different settlement account:
-
+
1. Go to Settings > Domains > Domain Name > Company Cards > Settings tab
2. Use the Expensify Card settlement account dropdown to select a new account
3. Click Save
-
+
+
## Change the settlement frequency
-
+
By default, the Expensify Cards settle on a daily cadence. However, you can choose to have the cards settle on a monthly basis.
-
+
1. Monthly settlement is only available if the settlement account hasn't had a negative balance in the last 90 days
2. There will be an initial settlement to settle any outstanding spend that happened before switching the settlement frequency
3. The date that the settlement is changed to monthly is the settlement date going forward (e.g. If you switch to monthly settlement on September 15th, Expensify Cards will settle on the 15th of each month going forward)
-
+
To change the settlement frequency:
1. Go to Settings > Domains > Domain Name > Company Cards > Settings tab
2. Click the Settlement Frequency dropdown and select Monthly
3. Click Save to confirm the change
-
-
+
+
+
## Declined Expensify Card transactions
As long as you have 'Receive realtime alerts' enabled, you'll get a notification explaining the decline reason. You can enable alerts in the mobile app by clicking on three-bar icon in the upper-left corner > Settings > toggle Receive realtime alerts on.
-
+
If you ever notice any unfamiliar purchases or need a new card, go to Settings > Account > Credit Card Import and click on Request a New Card right away.
-
+
Here are some reasons an Expensify Card transaction might be declined:
-
+
1. You have an insufficient card limit
- If a transaction amount exceeds the available limit on your Expensify Card, the transaction will be declined. It's essential to be aware of the available balance before making a purchase to avoid this - you can see the balance under Settings > Account > Credit Card Import on the web app or mobile app. Submitting expenses and having them approved will free up your limit for more spend.
-
+
2. Your card hasn't been activated yet, or has been canceled
- If the card has been canceled or not yet activated, it won't process any transactions.
-
+
3. Your card information was entered incorrectly. Entering incorrect card information, such as the CVC, ZIP or expiration date will also lead to declines.
-
+
4. There was suspicious activity
- If Expensify detects unusual or suspicious activity, we may block transactions as a security measure. This could happen due to irregular spending patterns, attempted purchases from risky vendors, or multiple rapid transactions. Check your Expensify Home page to approve unsual merchants and try again.
If the spending looks suspicious, we may do a manual due diligence check, and our team will do this as quickly as possible - your cards will all be locked while this happens.
-
5. The merchant is located in a restricted country
- Some countries may be off-limits for transactions. If a merchant or their headquarters (billing address) are physically located in one of these countries, Expensify Card purchases will be declined. This list may change at any time, so be sure to check back frequently: Belarus, Burundi, Cambodia, Central African Republic, Democratic Republic of the Congo, Cuba, Iran, Iraq, North Korea, Lebanon, Libya, Russia, Somalia, South Sudan, Syrian Arab Republic, Tanzania, Ukraine, Venezuela, Yemen, and Zimbabwe.
-
+
# FAQ
## What happens when I reject an Expensify Card expense?
-
-
Rejecting an Expensify Card expense from an Expensify report will simply allow it to be reported on a different report. You cannot undo a credit card charge.
-
+
If an Expensify Card expense needs to be rejected, you can reject the report or the specific expense so it can be added to a different report. The rejected expense will become Unreported and return to the submitter's Expenses page.
-
+
If you want to dispute a card charge, please message Concierge to start the dispute process.
-
+
If your employee has accidentally made an unauthorised purchase, you will need to work that out with the employee to determine how they will pay back your company.
-
-
+
+
## What happens when an Expensify Card transaction is refunded?
-
-
+
+
The way a refund is displayed in Expensify depends on the status of the expense (pending or posted) and whether or not the employee also submitted an accompanying SmartScanned receipt. Remember, a SmartScanned receipt will auto-merge with the Expensify Card expense.
-
+
- Full refunds:
If a transaction is pending and doesn't have a receipt attached (except for eReceipts), getting a full refund will make the transaction disappear.
If a transaction is pending and has a receipt attached (excluding eReceipts), a full refund will zero-out the transaction (amount becomes zero).
diff --git a/docs/articles/expensify-classic/expensify-card/Get-The-Card.md b/docs/articles/expensify-classic/expensify-card/Get-The-Card.md
deleted file mode 100644
index e5233a3732a3..000000000000
--- a/docs/articles/expensify-classic/expensify-card/Get-The-Card.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Get the Card
-description: Get the Card
----
-## Resource Coming Soon!
diff --git a/docs/articles/expensify-classic/expensify-card/Request-the-Card.md b/docs/articles/expensify-classic/expensify-card/Request-the-Card.md
new file mode 100644
index 000000000000..4830c0fffbcd
--- /dev/null
+++ b/docs/articles/expensify-classic/expensify-card/Request-the-Card.md
@@ -0,0 +1,49 @@
+---
+title: Request the Card
+description: Details on requesting the Expensify Card as an employee
+---
+# Overview
+
+Once your organization is approved for the Expensify Card, you can request a card!
+
+This article covers how to request, activate, and replace your physical and virtual Expensify Cards.
+
+# How to get your first Expensify Card
+
+An admin in your organization must first enable the Expensify Cards before you can receive a card. After that, an admin may assign you a card by setting a limit. You can think of setting a card limit as “unlocking” access to the card.
+
+If you haven’t been assigned a limit yet, look for the task on your account's homepage that says, “Ask your admin for the card!” This task allows you to message your admin team to make that request.
+
+Once you’re assigned a card limit, we’ll notify you via email to let you know you can request a card. A link within the notification email will take you to your account’s homepage, where you can provide your shipping address for the physical card. Enter your address, and we’ll ship the card to arrive within 3-5 business days.
+
+Once your physical card arrives in the mail, activate it in Expensify by entering the last four digits of the card in the activation task on your account’s homepage.
+
+# Virtual Card
+
+Once assigned a limit, a virtual card is available immediately. You can view the virtual card details via **Settings > Account > Credit Card Import > Show Details**. Feel free to begin transacting with the virtual card while your physical card is in transit – your virtual card and physical card share a limit.
+
+Please note that you must enable two-factor authentication on your account if you want to have the option to dispute transactions made on your virtual card.
+
+# Notifications
+
+To stay up-to-date on your card’s limit and spending activity, download the Expensify mobile app and enable push notifications. Your card is connected to your Expensify account, so each transaction on your card will trigger a push notification. We’ll also send you a push notification if we detect potentially fraudulent activity and allow you to confirm your purchase.
+
+# How to request a replacement Expensify Card
+
+You can request a new card anytime if your Expensify Card is lost, stolen, or damaged. From your Expensify account on the web, head to **Settings > Account > Credit Card Import** and click **Request a New Card**. Confirm the shipping information, complete the prompts, and your new card will arrive in 2 - 3 business days.
+
+Selecting the “lost” or “stolen” options will deactivate your current card to prevent potentially fraudulent activity. However, choosing the “damaged” option will leave your current card active so you can use it while the new one is shipped to you.
+
+If you need to cancel your Expensify Card and cannot access the website or mobile app, call our interactive voice recognition phone service (available 24/7). Call 1-877-751-5848 (US) or +44 808 196 0632 (Internationally).
+
+It's not possible to order a replacement card over the phone, so, if applicable, you would need to handle this step from your Expensify account.
+
+# FAQ
+
+## What if I haven’t received my card after multiple weeks?
+
+Reach out to support, and we can locate a tracking number for the card. If the card shows as delivered, but you still haven’t received it, you’ll need to confirm your address and order a new one.
+
+## I’m self-employed. Can I set up the Expensify Card as an individual?
+
+Yep! As long as you have a business bank account and have registered your company with the IRS, you are eligible to use the Expensify Card as an individual business owner.
diff --git a/docs/articles/expensify-classic/getting-started/Tips-And-Tricks.md b/docs/articles/expensify-classic/getting-started/Tips-And-Tricks.md
new file mode 100644
index 000000000000..b692bf466413
--- /dev/null
+++ b/docs/articles/expensify-classic/getting-started/Tips-And-Tricks.md
@@ -0,0 +1,72 @@
+---
+title: Tips and Tricks
+description: How to get started with setup tips for your Expensify account
+---
+
+# Overview
+In this article, we'll outline helpful tips for using Expensify, such as keyboard shortcuts and text formatting.
+
+# How to Format Text in Expensify
+You can use a basic markdown in report comments to emphasize or clarify your sentiments. This includes italicizing, bolding, and strikethrough for text, as well as adding basic hyperlinks.
+Formatting is consistent across both web and mobile applications, with three markdown options available for your report comments:
+- **Bold:** Place an asterisk on either side (*bold*)
+- **Italicize:** Place an underscore on either side (_italic_)
+- **Strikethrough:** Place a tilde on either side (~strikethrough~)
+
+# How to Use Keyboard Shortcuts
+Keyboard shortcuts can speed things up and simplify tasks. Expensify offers several shortcuts for your convenience. Let's explore them!
+- **Shift + ?** - Opens the keyboard shortcuts dialog
+- **Shift + G** - Prompts you for a reportID to open the report page for a specific report
+- **ESC** - Closes any shortcut dialog window
+- **Ctrl+Enter** - Submit a comment on a report from the comment field in the Report History & Comments section.
+- **Shift + P** - Takes you to the report’s policy when you’re on a report
+- **Shift + →** - Go to the next report
+- **Shift + ←** - Go to the previous report
+- **Shift + R** - Reloads the current page
+
+# How to Create a Copy of a Report
+If you have identical monthly expenses and want to copy them easily, visit your Reports page, check the box next to the report you would like to duplicate, and click "Copy" to duplicate all expenses (excluding receipt images).
+If you prefer, you can create a standard template for certain expenses:
+1. Go to the Reports page.
+2. Click "New Report."
+3. Assign an easily searchable name to the report.
+4. Click the green '+' button to add an expense.
+5. Choose "New Expense."
+6. Select the type of expense (e.g., regular expense, distance, time, etc.).
+7. Enter the expense details, code, and any relevant description.
+8. Click "Save."
+**Pro Tip:** If you use Scheduled Submit, place the template report under your individual workspace to avoid accidental submission. When you're ready to use it, check the report box, copy it, and make necessary changes to the name and workspace.
+
+# How to Enable Location Access on Web
+If you’d like to use features that rely on your current location, you will need to enable location permissions for Expensify. You can find instructions for enabling location settings on the three most common web browsers below. If your browser is not on the list, then please do a web search for your browser and “enable location settings”.
+
+## Chrome
+1. Open Chrome
+2. At the top right, click the three-dot Menu > Settings
+3. Click “Privacy and Security” and then “Site Settings”
+4. Click "Location"
+5. Check the “Not allowed to see your location” list to ensure that expensify.com and new.expensify.com are not listed. If they are, click the delete icon next to them to allow location access
+
+## Firefox
+1. Open Firefox
+2. In the URL bar enter “about:preferences”
+3. On the left-hand side select “Privacy & Security”
+4. Scroll down to Permissions
+5. Click on Settings next to Location
+6. If location access is blocked for expensify.com or new.expensify.com, you can update it here to allow access
+
+## Safari
+1. In the top menu bar, click Safari
+2. Then select Settings > Websites
+3. Click Location on the left-hand side
+4. If expensify.com or new.expensify.com have “Deny” set as their access, update it to “Ask” or “Allow”
+
+# Which browser works best with Expensify?
+We recommend using Google Chrome, but you can use Expensify on most major browsers, such as:
+- [Google Chrome](https://google.com/chrome/)
+- [Mozilla Firefox](https://mozilla.com/firefox)
+- [Microsoft Edge](https://microsoft.com/edge)
+- [Microsoft Internet Explorer](https://microsoft.com/ie). Please note: Microsoft has discontinued support and security updates for all versions below Version 11. This means those older versions may not work well. Due to the lack of security updates for the older versions, parts of our site may not be accessible. Please update your IE version or choose a different browser.
+- [Apple Safari (Apple devices only)](https://apple.com/safari)
+- [Opera](https://opera.com)
+It's always best practice to ensure you have the most recent updates for your browser and keep your operating system up to date.
diff --git a/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md b/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md
index 31f5aaf93032..dfc545c4c367 100644
--- a/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md
+++ b/docs/articles/expensify-classic/insights-and-custom-reporting/Other-Export-Options.md
@@ -14,7 +14,7 @@ From the **Expenses** page, you can export individual expenses into a CSV. From
3. Click **Export to** at the top right of the page
4. Choose the desired export option
-You can use one of the default templates or create your own template. The default templates and the option to export to a connected accounting package are only available on the **Reports** page. Visit the specific help page for your accounting package to learn more about how to get this set up.
+You can use one of the [default templates](https://help.expensify.com/articles/expensify-classic/insights-and-custom-reporting/Default-Export-Templates#gsc.tab=0) or [create your own template](https://help.expensify.com/articles/expensify-classic/insights-and-custom-reporting/Custom-Templates#gsc.tab=0). The default templates and the option to export to a connected accounting package are only available on the **Reports** page. Visit the specific help page for your accounting package to learn more about how to get this set up.
# How to export a report as a PDF
1. Go to the **Reports** page
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Bolt.md b/docs/articles/expensify-classic/integrations/travel-integrations/Bolt.md
deleted file mode 100644
index 3ee1c8656b4b..000000000000
--- a/docs/articles/expensify-classic/integrations/travel-integrations/Bolt.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-title: Coming Soon
-description: Coming Soon
----
-## Resource Coming Soon!
diff --git a/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md b/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md
index 3ee1c8656b4b..2e6bd335ce4c 100644
--- a/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md
+++ b/docs/articles/expensify-classic/workspace-and-domain-settings/Tags.md
@@ -1,5 +1,94 @@
---
-title: Coming Soon
-description: Coming Soon
+title: Workspace Tags
---
-## Resource Coming Soon!
+# Overview
+You can use tags to assign expenses to a specific department, project, location, cost center, and more.
+
+Note that tags function differently depending on whether or not you connect Expensify to a direct account integration (i.e., QuickBooks Online, NetSuite, etc.). With that said, this article covers tags that work for all account setups.
+# How to use Tags
+Tags are a workspace-level feature. They’re generally used to code expenses to things like customers, projects, locations, or departments. at the expense level. You can have different sets of tags for different workspaces, allowing you to customize coding for cohorts of employees.
+
+With that said, tags come in two forms: single tags and multi-level tags.
+
+## Single Tags
+Single tags refer to the simplest version of tags, allowing users to code expenses on a single level. With a single tag setup, users will pick from the list of tags you created and make a single selection on each expense.
+## Multi-Level Tags
+On the other hand, Multi-Level Tags refer to a more advanced tagging system that allows you to code expenses in a hierarchical or nested manner. Unlike single tags, which are standalone labels, multi-level tags enable you to create a structured hierarchy of tags, with sub-tags nested within parent tags. This feature is particularly useful for organizations that require a more detailed and organized approach to expense tracking.
+# How to import single tags (no accounting integration connected)
+## Add single tags via spreadsheet
+To set up Tags, follow these steps:
+- Go to **Settings > Workspace > Group / Individual > [Workspace name] > Tags**.
+- You can choose to add tags one by one, or upload them in bulk via a spreadsheet.
+
+After downloading the CSV and creating the tags you want to import, go to the Tags section in the policy editor: Settings > Workspaces > Group > [Workspace name] > Tags
+ Enable multi-level tags by toggling the button.
+Click "Import from Spreadsheet" to bring in your CSV.
+ Indicate whether the first line contains the tag header.
+Choose if the tag list is independent or dependent (matching your CSV).
+Decide if your tags list includes GL codes.
+Upload your CSV or TSV file.
+Confirm your file and update your tags list.
+## Manually add single tags
+
+If you need to add Tags to your workspace manually, you can follow the steps below.
+
+On web:
+
+1. Navigate to Settings > Workspace > Group / Individual > [Workspace name] > Tags.
+2. Add new tags under Add a Category.
+
+On mobile:
+
+1. Tap the three-bar menu icon at the top left corner of the app
+2. Tap on Settings in the menu on the left side
+3. Scroll to the Workspace subhead and click on tags listed underneath the default policy
+4. Add new categories by tapping the + button in the upper right corner. To delete a category, on iOS swipe left, on Android press and hold. Tap a category name to edit it.
+
+# How to import multi-level tags (no accounting integration connected)
+To use multi-level tags, go to the Tags section in your workspace settings.
+Toggle on "Do you want to use multiple levels of tags?"
+
+This feature is available for companies with group workspaces and helps accountants track more details in expenses.
+
+If you need to make changes to your multi-level tags, follow these steps:
+1. Start by editing them in a CSV file.
+2. Import the revised tags into Expensify.
+3. Remember to back up your tags! Uploading a CSV will replace your existing settings.
+4. Safest Option: Download the old CSV from the Tags page using 'Export to CSV,' make edits, then import it.
+
+## Manage multi-level tags
+Once multi-level tagging has been set up, employees will be able to choose more than one tag per expense. Based on the choice made for the first tag, the second subset of tag options will appear. After the second tag is chosen, more tag lists can appear, customizable up to 5 tag levels.
+
+### Best Practices
+- Multi-level tagging is available for companies on group workspaces and is intended to help accountants track additional information at the expense line-item level.
+- If you need to make any changes to the Tags, you need to first make them on the CSV and import the revised Tags into Expensify.
+- Make sure to have a backup of your tags! Every time you upload a CSV it will override your previous settings.
+- The easiest way to keep the old CSV is to download it from the Tags page by clicking Export to CSV, editing the list, and then importing it to apply the changes.
+
+
+# How to import tags with an accounting integration connected
+If you have connected Expensify to a direct integration such as QuickBooks Online, QuickBooks Desktop, Sage Intacct, Xero, or NetSuite, then Expensify automatically imports XYZ from your accounting system as tags.
+
+When you first connect your accounting integration you’ll configure classes, customers, projects, departments locations, etc. to import as tags in Expensify.
+
+If you need to update your tags in Expensify, you will first need to update them in your accounting system, then sync the connection in Expensify by navigating to Settings > Workspace > Group > [Workspace Name] > Connection > Sync Now.
+
+Alternatively, if you update the tag details in your accounting integration, be sure to sync the policy connection so that the updated information is available on the workspace.
+
+# Deep Dive
+## Make tags required
+You can require tags for any workspace expenses by enabling People must tag expenses on the Tags page by navigating to Settings > Workspace > Group > [Workspace Name] > Tags.
+# FAQ
+
+## What are the different tag options?
+If you want your second tag to depend on the first one, use dependent tags. Include GL codes if needed, especially when using accounting integrations.
+For other scenarios, like not using accounting integrations, use independent tags, which can still include GL codes if necessary.
+
+
+## Are the multi-level tags only available with a certain subscription (pricing plan)?
+Multi-level tagging is only available with the Control type policy.
+
+## I can’t see "Do you want to use multiple level tags" feature on my company's expense workspace. Why is that?
+If you are connected to an accounting integration, you will not see this feature. You will need to add those tags in your integration first, then sync the connection.
+
+
diff --git a/docs/articles/new-expensify/getting-started/Security.md b/docs/articles/new-expensify/getting-started/Security.md
new file mode 100644
index 000000000000..5c8eee7ae60e
--- /dev/null
+++ b/docs/articles/new-expensify/getting-started/Security.md
@@ -0,0 +1,53 @@
+---
+title: Security
+description: Expensify prioritizes data security and maintains strict compliance standards to safeguard users' sensitive information.
+---
+
+
+# Overview
+
+We take security seriously. Our measures align with what banks use to protect sensitive financial data. We regularly test and update our security to stay ahead of any threats. Plus, we're checked daily by McAfee for extra reassurance against hackers. You can verify our security strength below or on the McAfee SECURE site .
+
+Discover how Expensify safeguards your information below!
+
+## The Gold Standard of Security
+
+Expensify follows the highest standard of security, known as the Payment Card Industry Data Security Standard. This standard is used by major companies like PayPal, Visa, and banks to protect online credit card information. It covers many aspects of how systems work together securely. You can learn more about it on the PCI-DSS website . And, Expensify is also compliant with SSAE 16!
+
+
+## Data and Password Encryption
+
+When you press 'enter,' your data transforms into a secret code, making it super secure. This happens whether it's moving between your browser and our servers or within our server network. In tech talk, we use HTTPS+TLS for all web connections, ensuring your information is encrypted at every stage of the journey. This means your data is always protected!
+
+## Account Safety
+
+Protecting your data on our servers is our top priority. We've taken strong measures to ensure your data is safe when it travels between you and us and when it's stored on our servers.
+In our first year, we focused on creating a super-reliable, geographically redundant, and PCI compliant data center. This means your data stays safe, and our systems stay up and running.
+We use a dual-control key, which only our servers know about. This key is split into two parts and stored in separate secure places, managed by different Expensify employees.
+With this setup, sensitive data stays secure and can't be accessed outside our secure servers.
+
+## Our Commitment to GDPR
+
+The General Data Protection Regulation (GDPR), introduced by the European Commission, is a set of rules to strengthen and unify data protection for individuals in the European Union (EU). It also addresses the transfer of personal data outside the EU. This regulation applies not only to EU-based organizations but also to those outside the EU that handle the data of EU citizens. The compliance deadline for GDPR was May 25, 2018.
+
+Our commitment to protecting the privacy of our customer’s data includes:
+
+- Being active participants in the EU-US Privacy Shield and Swiss-US Privacy Shield Frameworks.
+- Undergoing annual SSAE-18 SOC 1 Type 2 audit by qualified, independent third-party auditors.
+- Maintaining PCI-DSS compliance.
+- Leveraging third-party experts to conduct yearly penetration tests.
+- All employees and contractors are subject to background checks (refreshed. annually), sign non-disclosure agreements, and are subject to ongoing security and privacy training.
+
+
+We have worked diligently to ensure we comply with GDPR. Here are some key changes we made:
+
+
+- **Enhanced Security and Data Privacy**: We've strengthened our security measures and carefully reviewed our privacy policies to align with GDPR requirements.
+- **Dedicated Data Protection Officer**: We've appointed a dedicated Data Protection Officer who can be reached at [privacy@expensify.com](mailto:privacy@expensify.com) for any privacy-related inquiries.
+- **Vendor Agreements**: We've signed Data Processing Addendums (DPAs) with all our vendors to ensure your data is handled safely during onward transfers.
+- **Transparency**: You can find details about the sub-processors we use on our website.
+- **Privacy Shield Certification**: We maintain certifications for the E.U.-U.S. Privacy Shield and the Swiss-U.S. Privacy Shield, which help secure international data transfers.
+- **GDPR Compliance**: We have a Data Processing Addendum that outlines the terms to meet GDPR requirements. You can request a copy by contacting [concierge@expensify.com](mailto:concierge@expensify.com).
+- **User Control**: Our product tools allow users to export data, manage preferences, and close accounts anytime.
+
+**Disclaimer**: Please note that the information on this page is for informational purposes only and is not intended as legal advice. It's essential to consult with legal and professional counsel to understand how GDPR may apply to your specific situation.
diff --git a/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md b/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md
index aa5f40ee4e5d..7a0717eeb5d1 100644
--- a/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md
+++ b/docs/articles/new-expensify/integrations/accounting-integrations/QuickBooks-Online.md
@@ -1,5 +1,320 @@
---
-title: QuickBooks Online
-description: QuickBooks Online
+title: The QuickBooks Online Integration
+description: Expensify's integration with QuickBooks Online streamlines your expense management.
+
---
-## Resource Coming Soon!
+# Overview
+
+The Expensify integration with QuickBooks Online brings in your expense accounts and other data and even exports reports directly to QuickBooks for easy reconciliation. Plus, with advanced features in QuickBooks Online, you can fine-tune coding settings in Expensify for automated data export to optimize your accounting workflow.
+
+## Before connecting
+
+It's crucial to understand the requirements based on your specific QuickBooks subscription:
+
+- While all the features are available in Expensify, their accessibility may vary depending on your QuickBooks Online subscription.
+- An error will occur if you try to export to QuickBooks with a feature enabled that isn't part of your subscription.
+- Please be aware that Expensify does not support the Self-Employed subscription in QuickBooks Online.
+
+# How to connect to QuickBooks Online
+
+## Step 1: Setup employees in QuickBooks Online
+
+Employees must be set up as either Vendors or Employees in QuickBooks Online. Make sure to include the submitter's email in their record.
+
+If you use vendor records, you can export as Vendor Bills, Checks, or Journal Entries. If you use employee records, you can export as Checks or Journal Entries (if exporting against a liability account).
+
+Additional Options for Streamlined Setup:
+
+- Automatic Vendor Creation: Enable “Automatically Create Entities” in your connection settings to automatically generate Vendor or Employee records upon export for submitters that don't already exist in QBO.
+- Employee Setup Considerations: If setting up submitters as Employees, ensure you activate QuickBooks Online Payroll. This will grant access to the Employee Profile tab to input employee email addresses.
+
+## Step 2: Connect Expensify and QuickBooks Online
+
+- Navigate to Settings > Workspaces > Group > [Workspace Name] > Connections > QuickBooks Online. Click Connect to QuickBooks.
+- Enter your QuickBooks Online Administrator’s login information and choose the QuickBooks Online Company File you want to connect to Expensify (you can connect one Company File per Workspace). Then Click Authorize.
+- Enter your QuickBooks Online Administrator’s login information and choose the QuickBooks Online Company File you want to connect to Expensify (you can connect one Company File per Workspace):
+
+Exporting Historical Reports to QuickBooks Online:
+
+After connecting QuickBooks Online to Expensify, you may receive a prompt to export all historical reports from Expensify. To export multiple reports at once, follow these steps:
+
+a. Go to the Reports page on the web.
+
+b. Tick the checkbox next to the reports you want to export.
+
+c. Click 'Export To' and select 'QuickBooks Online' from the drop-down list.
+
+If you don't want to export specific reports, click “Mark as manually entered” on the report.
+
+# How to configure export settings for QuickBooks Online
+
+Our QuickBooks Online integration offers a range of features. This section will focus on Export Settings and how to set them up.
+
+## Preferred Exporter
+
+Any Workspace admin can export to your accounting integration, but the Preferred Exporter can be chosen to automate specific steps. You can set this role from Settings > Workspaces > Group > [Workspace Name] > Connections > Configure > Export > Preferred Exporter.
+
+The Preferred Exporter:
+
+- Is the user whose Concierge performs all automated exports on behalf of.
+- Is the only user who will see reports awaiting export in their **Home.**
+- Must be a **Domain Admin** if you have set individual GL accounts for Company Card export.
+- Must be a **Domain Admin** if this is the Preferred Workspace for any Expensify Card domain using Automatic Reconciliation.
+
+## Date
+
+When exporting reports to QuickBooks Online, you can choose the report's **submitted date**, the report's **exported date**, or the **date of the last expense on the report.**
+
+Most export options (Check, Journal Entry, and Vendor Bill) will create a single itemized entry with one date.
+Please note that if you choose a Credit Card or Debit Card for non-reimbursable expenses, we'll use the transaction date on each expense during export.
+
+# Reimbursable expenses
+
+Reimbursable expenses export to QuickBooks Online as:
+
+- Vendor Bills
+- Checks
+- Journal Entries
+
+## Vendor bill (recommended)
+
+This is a single itemized vendor bill for each Expensify report. If the accounting period is closed, we will post the vendor bill on the first day of the next open period. If you export as Vendor Bills, you can also choose to Sync reimbursed reports (set on the Advanced tab). **An A/P account is required to export to a vendor bill. Here is a screenshot of how your expenses map in QuickBooks.**
+
+The submitter will be listed as the vendor in the vendor bill.
+
+## Check
+
+This is a single itemized check for each Expensify report. You can mark a check to be printed later in QuickBooks Online.
+
+## Journal entry
+
+This is a single itemized journal entry for each Expensify report.
+
+# Non-reimbursable expenses
+
+Non-reimbursable expenses export to QuickBooks Online as:
+
+- Credit Card expenses
+- Debit Card Expenses
+- Vendor Bills
+
+## Credit/debit card
+
+Using Credit/Debit Card Transactions:
+
+- Each expense will be exported as a bank transaction with its transaction date.
+- If you split an expense in Expensify, we'll consolidate it into a single credit card transaction in QuickBooks with multiple line items posted to the corresponding General Ledger accounts.
+
+Pro-Tip: To ensure the payee field in QuickBooks Online reflects the merchant name for Credit Card expenses, ensure there's a matching Vendor in QuickBooks Online. Expensify checks for an exact match during export. If none are found, the payee will be mapped to a vendor we create and labeled as Credit Card Misc. or Debit Card Misc.
+
+If you centrally manage your company cards through Domains, you can export expenses from each card to a specific account in QuickBooks.
+
+## Vendor Bill
+
+- A single detailed vendor bill is generated for each Expensify report. If the accounting period is closed, the vendor bill will be posted on the first day of the next open period. If you choose to export non-reimbursable expenses as Vendor Bills, you can assign a default vendor to the bill.
+- The export will use your default vendor if you have Default Vendor enabled. If the Default Vendor is disabled, the report's submitter will be set as the Vendor in QuickBooks.
+
+Billable Expenses:
+
+- In Expensify, you can designate expenses as billable. These will be exported to QuickBooks Online with the billable flag. - This feature applies only to expenses exported as Vendor Bills or Checks. To maximize this functionality, ensure that any billable expense is associated with a Customer/Job.
+
+## Export Invoices
+
+If you are creating Invoices in Expensify and exporting these to QuickBooks Online, this is the account the invoice will appear against.
+
+# Configure coding for QuickBooks Online
+
+The coding tab is where your information is configured for Expensify; this will allow employees to code expenses and reports accurately.
+
+- Categories
+- Classes and/or Customers/Projects
+- Locations
+- Items
+- Tax
+
+## Categories
+
+QuickBooks Online expense accounts will be automatically imported into Expensify as Categories.
+
+## Account Import
+
+Equity type accounts will also be imported as categories.
+
+Important notes:
+
+- Other Current Liabilities can only be exported as Journal Entries if the submitter is set up as an Employee in QuickBooks.
+- Exchange Gain or Loss detail type does not import.
+
+Recommended steps to take after importing the expense accounts from QuickBooks to Expensify:
+
+- Go to Settings > Workspaces > Groups > [Workspace Name] > Categories to see the accounts imported from QuickBooks Online.
+- Use the enable/disable button to choose which Categories to make available to your employees, and set Category specific rules via the blue settings cog.
+- If necessary, edit the names of imported Categories to make expense coding easier for your employees. (Please Note: If you make any changes to these accounts in QuickBooks Online, the category names on Expensify's side will revert to match the name of the account in QuickBooks Online the next time you sync).
+- If you use Items in QuickBooks Online, you can import them into Expensify as Categories.
+
+Please note that each expense has to have a category selected to export to QuickBooks Online. The chosen category has to be imported from QuickBooks Online and cannot be manually created within the Workspace settings.
+
+## Classes and Customers/Projects
+
+If you use Classes or Customers/Projects in QuickBooks Online, you can import those into Expensify as Tags or Report Fields:
+
+- Tags let you apply a Class and/or Customer/Project to each expense
+- Report Fields enables you to apply a Class and/or Customer/Project to all expenses on a report.
+
+Note: Although Projects can be imported into Expensify and coded to expenses, due to the limitations of the QuickBooks API, expenses cannot be created within the Projects module in QuickBooks.
+
+## Locations
+
+Locations can be imported into Expensify as a Report Field or, if you export reimbursable expenses as Journal Entries and non-reimbursable expenses as Credit/Debit Card, you can import Locations as Tags.
+
+## Items
+
+If you use Items in QuickBooks Online, you can import Items defined with Purchasing Information (with or without Sales Information) into Expensify as Categories.
+## Tax
+
+- Using our tax tracking feature, you can assign a tax rate and amount to each expense.
+-To activate tax tracking, go to connection configuration and enable it. This will automatically import purchasing taxes from QuickBooks Online into Expensify.
+- After the connection is set, navigate to Settings > Worspaces > Groups > Workspace Name] > Tax. Here, you can view the taxes imported from QuickBooks Online.
+- Use the enable/disable button to choose which taxes are accessible to your employees.
+- Set a default tax for the Company Workspace, which will automatically apply to all new expenses.
+- Please note that, at present, tax cannot be exported to Journal Entries in QuickBooks Online.
+- Expensify performs a daily sync to ensure your information is up-to-date. This minimizes errors from outdated QuickBooks Online data and saves you time on syncing.
+
+# How to configure advanced settings for QuickBooks Online
+
+The advanced settings are where functionality for automating and customizing the QuickBooks Online integration can be enabled.
+Navigate to this section of your Workspace by following Settings > Workspaces > Group > [Workspace Name] > Connections > Configure button > Advanced tab.
+## Auto Sync
+With QuickBooks Online auto-sync, once a non-reimbursable report is final approved in Expensify, it's automatically queued for export to QuickBooks Online. For expenses eligible for reimbursement with a linked business bank account, they'll sync when marked as reimbursed.
+
+## Newly Imported Categories
+
+This setting determines the default status of newly imported categories from QuickBooks Online to Expensify, either enabled or disabled.
+
+## Invite Employees
+
+Enabling this automatically invites all Employees from QuickBooks Online to the connected Expensify Company Workspace. If not, you can manually invite or import them using a CSV file.
+
+## Automatically Create Entities
+
+When exporting reimbursable expenses as Vendor Bills or Journal Entries, Expensify will automatically create a vendor in QuickBooks if one doesn't exist. It will also generate a customer when exporting Invoices.
+
+## Sync Reimbursed Reports
+
+Enabling this marks the Vendor Bill as paid in QuickBooks Online when you reimburse a report via ACH direct deposit in Expensify. If reimbursing outside Expensify, marking the Vendor Bill as paid will automatically in QuickBooks Online update the report as reimbursed in Expensify. Note: After enabling this feature, select your QuickBooks Account in the drop-down, indicating the bank account for reimbursements.
+
+## Collection Account
+
+If you are exporting Invoices from Expensify to Quickbooks Online, this is the account the Invoice will appear against once marked as Paid.
+
+# Deep Dive
+
+## Preventing Duplicate Transactions in QuickBooks
+
+When importing a banking feed directly into QuickBooks Online while also importing transactions from Expensify, it's possible to encounter duplicate entries in QuickBooks. To prevent this, follow these steps:
+
+Step 1: Complete the Approval Process in Expensify
+
+- Before exporting any expenses to QuickBooks Online, ensure they are added to a report and the report receives approval. Depending on your Workspace setup, reports may require approval from one or more individuals. The approval process concludes when the last user who views the report selects "Final Approve."
+
+Step 2: Exporting Reports to QuickBooks Online
+
+- To ensure expenses exported from Expensify match seamlessly in the QuickBooks Banking platform, make sure these expenses are marked as non-reimbursable within Expensify and that “Credit Card” is selected as the non-reimbursable export option for your expenses.
+
+Step 3: Importing Your Credit Card Transactions into QuickBooks Online
+
+- After completing Steps 1 and 2, you can import your credit card transactions into QuickBooks Online. These imported banking transactions will align with the ones brought in from Expensify. QuickBooks Online will guide you through the process of matching these transactions, similar to the example below:
+
+## Tax in QuickBooks Online
+
+If your country applies taxes on sales (like GST, HST, or VAT), you can utilize Expensify's Tax Tracking along with your QuickBooks Online tax rates. Please note: Tax Tracking is not available for Workspaces linked to the US version of QuickBooks Online. If you need assistance applying taxes after reports are exported, contact QuickBooks.
+
+To get started:
+
+- Go to Settings > Workpaces > Group > [Workspace Name] > Connections, and click Configure.
+- Navigate to the Coding tab.
+- Turn on 'T.''.
+- Click Save. This imports the Tax Name and rate from QuickBooks Online.
+- Visit Settings > Workspaces > Group > [Workspace Name] > Tax to view the imported taxes.
+- Use the enable/disable button in the Tax tab to choose which taxes your employees can use.
+
+Remember, you can also set a default tax rate for the entire Workspace. This will be automatically applied to all new expenses. The user can still choose a different tax rate for each expense.
+
+Tax information can't be sent to Journal Entries in QuickBooks Online. Also, when dealing with multiple tax rates, where one receipt has different tax rates (like in the EU, UK, and Canada), users should split the expense into the respective parts and set the appropriate tax rate for each part.
+
+## Multi-currency
+
+When working with QuickBooks Online Multi-Currency, there are some things to remember when exporting Vendor Bills and Check! Make sure the vendor's currency and the Accounts Payable (A/P) bank account match.
+
+In QuickBooks Online, the currency conversion rates are not applied when exporting. All transactions will be exported with a 1:1 conversion rate, so for example, if a vendor's currency is CAD (Canadian Dollar) and the home currency is USD (US Dollar), the export will show these currencies without applying conversion rates.
+
+To correct this, you must manually update the conversion rate after the report has been exported to QuickBooks Online.
+
+Specifically for Vendor Bills:
+
+If multi-currency is enabled and the Vendor's currency is different from the Workspace currency, OR if QuickBooks Online home currency is foreign from the Workspace currency, then:
+
+- We create the Vendor Bill in the Vendor's currency (this is a QuickBooks Online requirement - we don't have a choice)
+- We set the exchange rate between the home currency and the Vendor's currency
+- We convert line item amounts to the vendor's currency
+
+Let's consider this example:
+
+- QuickBooks Online home currency is USD
+- Vendor's currency is VND
+- Workspace (report) currency is JPY
+
+Upon export, we:
+
+1. Specified the bill is in VND
+2. Set the exchange rate between VND and USD (home currency), computed at the time of export.
+3. Converted line items from JPY (currency in Expensify) to VND
+4. QuickBooks Online automatically computed the USD amount (home currency) based on the exchange rate we specified
+5. Journal Entries, Credit Card, and Debit Card:
+
+Multi-currency exports will fail as the account currency must match both the vendor and home currencies.
+
+## Report Fields
+
+Report fields are a handy way to collect specific information for a report tailored to your organization's needs. They can specify a project, business trip, client, location, and more!
+
+When integrating Expensify with Your Accounting Software, you can create your report fields in your accounting software so the next time you sync your Workspace, these fields will be imported into Expensify.
+
+To select how a specific field imports to Expensify, head to Settings > Workspaces > Group >
+[Workspace Name] > Connections > Accounting Integrations > QuickBooks Online > Configure > Coding.
+
+Here are the QuickBooks Online fields that can be mapped as a report field within Expensify:
+
+- Classes
+- Customers/Projects
+- Locations
+
+# FAQ
+
+## What happens if the report can't be exported to QuickBooks Online automatically?
+
+If a report encounters an issue during automatic export to QuickBooks Online, you'll receive an email with details about the problem, including any specific error messages. These messages will also be recorded in the report's history section.
+
+The report will be placed in your Home for your attention. You can address the issues there. If you need further assistance, refer to our QuickBooks Online Export Errors page or export the report manually.
+
+## How can I ensure that I final approve reports before they're exported to QuickBooks Online?
+
+To ensure reports are reviewed before export, set up your Workspaces with the appropriate workflow in Expensify. Additionally, consider changing your Workspace settings to enforce expense Workspace workflows strictly. This guarantees that your Workspace's workflow is consistently followed.
+
+## What happens to existing approved and reimbursed reports if I enable Auto Sync?
+
+- If Auto Sync was disabled when your Workspace was linked to QuickBooks Online, enabling it won't impact existing reports that haven't been exported.
+- If a report has been exported and reimbursed via ACH, it will be automatically marked as paid in QuickBooks Online during the next sync.
+- If a report has been exported and marked as paid in QuickBooks Online, it will be automatically marked as reimbursed in Expensify during the next sync.
+- Reports that have yet to be exported to QuickBooks Online won't be automatically exported.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md b/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md
new file mode 100644
index 000000000000..cf2f0f59a4a0
--- /dev/null
+++ b/docs/articles/new-expensify/workspace-and-domain-settings/Domain-Settings-Overview.md
@@ -0,0 +1,140 @@
+---
+title: Domains
+description: Want to gain greater control over your company settings in Expensify? Read on to find out more about our Domains feature and how it can help you save time and effort when managing your company expenses.
+---
+
+# Overview
+Domains is a feature in Expensify that allows admins to have more nuanced control over a specific Expensify activity, as well as providing a bird’s eye view of company card expenditure. Think of it as your command center for things like managing user account access, enforcing stricter Workspace rules for certain groups, or issuing cards and reconciling statements.
+There are several settings within Domains that you can configure so that you have more control and visibility into your organization’s settings. Those features are:
+- Company Cards
+- Domain Admins
+- Domain Members
+ - Two-Factor Authentication
+- Domain Groups
+ - Domain Group Settings
+- Reporting Tools
+- SAML
+
+There are two ways to use Domains – as an unverified domain or a verified domain. An unverified domain allows you to import Company Cards and manage them, whereas a verified domain allows you to do that in addition to:
+1. Receive vendor bills in Expensify
+2. Fine-tune user restrictions using domain Groups
+3. Configure SAML SSO for easier login to Expensify
+4. Set vacation delegates for your domain members
+5. Use consolidated domain billing
+
+# How to claim a domain
+To use the domains feature with an unverified domain, you’ll need to claim the domain first.
+To claim a domain, you need to be a Workspace Admin with a company email address. This allows you to manage company bills, company cards, and reconciliation. Claiming requires an email matching your company's domain.
+1. Create an Expensify account
+2. Set up an expense Workspace
+3. Go to **Settings > _Domains_**.
+Whichever member runs through those steps will automatically be made a Domain Admin.
+
+
+# How to verify a domain
+To use the domains feature with a verified domain, you’ll want to go through the steps of verifying it.
+
+To verify domain ownership, follow these steps:
+1. Log in to your DNS service provider, which could be your Domain Name Registrar like NameCheap or GoDaddy, a dedicated DNS service provider like DNSMadeEasy or Amazon Route53, or managed internally by your company's IT department.
+2. Find the page for editing DNS records for expensify.com. This might be labeled as DNS Management or Zone File Editor.
+3. Add a new TXT record and set the value as: **532F6180D8**
+4. Save your changes
+5. Click the Verify button to confirm domain ownership
+
+After successful verification, you can remove the TXT DNS record. Please note that an email will be sent to all Expensify users on the domain to inform them that their accounts will be under Domain Control after verification.
+
+**Tips:**
+Not sure how to do this? Check the below guides from some of the most popular hosts on the web:
+[123-reg.co.uk](https://www.123-reg.co.uk/)
+[One.com](https://www.one.com/en/)
+[Wix.com](https://www.wix.com/)
+Google/GSuite
+[Godaddy](https://www.godaddy.com/)
+When creating the TXT record, input only the code and no other values or information.
+You can always confirm if you added the TXT code correctly here: https://viewdns.info/dnsrecord/?domain=[enterdomainhere]
+
+# Domain settings
+
+## Domain Admins
+Domain Admins have full authority over domain settings. They can modify member group names and rules, link or modify Company Cards, and add or remove domain members and other admins.
+
+### Adding a Domain Admin
+1. Head to **Settings > Domains > [Domain Name] > Domain Admins**
+2. In the "Email or Phone" field, type in the email address of the person you want to make a Domain Admin (this can be any email not specifically tied to the domain)
+3. Click "Add Admin"
+
+### Removing a Domain Admin:
+1. If you're already a Domain Admin, go to **Settings > Domains > [Domain Name] > Domain Admins**
+2. Locate the list of Domain Admins and find the one you want to remove
+3. Next to the Domain Admin's name, click the red trash can icon. This will remove that person from the Domain Admin role
+
+## Domain Members
+A domain member is a user associated with a specific domain (usually a company or another group) in Expensify and typically managed by a Domain Admin. This is also where you can enable Two-Factor authentication for your domain.
+
+### Adding users to the domain
+When a Domain Admin adds a user to the domain, that will create a new Expensify account for that user, and they'll receive invitations to set up their account. Users can also join a verified domain by creating their own account, as long as they have an email address associated with that domain (e.g. yourname@yourcompany.com). Once they have verified the account, all Domain Admins will be notified, and the employee will be added to the Default Group.
+**Important Note:** If someone who isn't a Domain Admin invites a user to a Workspace before they're invited to the domain, their account will be created, but in a closed state. A closed state means that the account cannot be used until it has been validated. Once the Domain Admin has invited the user, the user will receive a magic link to verify their account, sign in, and open the account completely.
+
+### How to add users
+1. In your web account, go to **Settings > Domains > [Domain Name] > Domain Admins**
+2. In the email field, enter the user you want to invite. This will create their Expensify account and send them an invitation
+
+### Removing users from the Domain
+Removing a user means taking them out of your domain and closing their Expensify account completely if they don't have another login. Be cautious because closing an account is permanent and deletes any unsubmitted or processing reports.
+
+### How to remove users
+In your web account, go to **Settings > Domains > [Domain Name] > Domain Admins**
+Check the box next to the employee's name you want to remove, then click “Close Accounts”.
+
+### Important notes about closing accounts through Domain settings:
+If a user has a Secondary Login linked to their Expensify account, they can still access their account after it's closed in the domain. This is helpful for accessing financial data, like tax-related receipts.
+Closing an account through the domain permanently removes any unsubmitted receipts/reports. Make sure to approve or reimburse all employee reports before closing an account.
+If an employee doesn't have a Secondary Login, they'll be automatically removed from the group Workspace. If they have a Secondary Login, it will continue to be associated with the group Workspace.
+
+## Domain Groups
+Domain Groups can be accessed if you have verified your domain. Groups are used to set rules or permissions for groups of users so you can enforce multiple different expense workspaces and rules. If you are a Domain Admin, you can create and edit Domain Groups under **Settings > Domains > _Domain Name_ > Groups**.
+
+### Creating Domain Groups
+1. In your Expensify account on the web, navigate to **Settings > Domains > _Domain Name_ > Groups**
+2. Select “Create Group” to create the group. This will allow you to name the Group, as well as configure permissions that will apply to members of the Group.
+
+### Adding members to a Domain Group
+1. In your Expensify account on the web, navigate to **Settings > Domains > [Domain Name] > Domain Members**
+2. Select the checkbox next to the domain members you wish to add to the Domain Group
+3. Select “Add to Group” to select the Group you wish to add them to
+
+### Editing Domain Groups
+1. In your Expensify account on the web, navigate to **Settings > Domains > _Domain Name_ > Groups**
+2. Next to the Group you wish to edit, select “Edit”
+3. This will open the Edit Permission Group pane, where you can edit the rules and permissions for that group
+4. Make your edits and click “Save”
+
+## Domain Group settings
+These are the settings that can be customized for each group you have created. Typically, companies use two groups (Employees and Managers) and enforce stricter rules for Employees. The settings are:
+- Strict Workspace Enforcement: When enabled, all Workspace rules must be followed for a report to be submitted. If a rule is violated, the report can't be submitted until the issue is fixed. Employees can't bypass this by dismissing notifications.
+- Login Restrictions: Enabling this prevents users from using non-company email addresses as their primary login. Secondary logins are still allowed.
+- Workspace Creation and Removal Restrictions: This feature stops users from creating new group workspaces or unsubscribing from existing workspaces. Admins who need these abilities should be in a separate group with this restriction turned off.
+- Preferred Workspace: When enabled, group members can only create reports under one designated Workspace. They can move a report to a different Workspace or their personal one later if needed. This helps keep personal and company expenses separate. If a company card uses a specific Workspace, this setting overrides it for more control over company card expenses.
+- Setting a Preferred Workspace: If Preferred Workspace is on, you can choose a default group Workspace for all Group Members.
+
+## SAML
+To enable SAML SSO in Expensify you will first need to claim and verify your domain. Once you have a verified domain, you can access SAML SSO by navigating to **Settings > Domains > _Domain Name_ > SAML**
+
+## Enable Two-Factor Authentication (2FA)
+1. As a Domain Admin, head to: **Settings > Domains > _Your Domain Name_ > Domain Members**
+2. Turn on Two Factor Authentication by toggling it to ENABLED
+3. Any Domain members that do not have two-factor authentication enabled will be asked to set it up on their Home page when they next log in, and won't be able to use Expensify until they do.
+4. To turn it off, simply toggle it off and refresh the page.
+
+**Tips:**
+- When using SAML, two-factor authentication cannot be required.
+- For disputing digital Expensify Card purchases, two-factor authentication must be enabled.
+- It might take up to 2 hours for domain-level enforcement to take effect, and users will be prompted to configure their individual 2FA settings on their next login to Expensify.
+
+# FAQ
+
+## How many domains can I have?
+You can manage multiple domains by adding them through **Settings > Domains > New Domain**. However, to verify additional domains, you must be a Workspace Admin on a Control Workspace. Keep in mind that the Collect plan allows verification for just one domain.
+
+## What’s the difference between claiming a domain and verifying a domain?
+Claiming a domain is limited to users with matching email domains, and allows Workspace Admins with a company email to manage bills, company cards, and reconciliation. Verifying a domain offers extra features and security.
diff --git a/docs/assets/images/Auto-Reconciliation_Image2.png b/docs/assets/images/Auto-Reconciliation_Image2.png
index 5c7ed2d6b7ea..4e53dc49f6f1 100644
Binary files a/docs/assets/images/Auto-Reconciliation_Image2.png and b/docs/assets/images/Auto-Reconciliation_Image2.png differ
diff --git a/docs/assets/images/Auto-Reconciliaton_Image1.png b/docs/assets/images/Auto-Reconciliaton_Image1.png
index 9fcb7e316aaf..a9a4a33954c8 100644
Binary files a/docs/assets/images/Auto-Reconciliaton_Image1.png and b/docs/assets/images/Auto-Reconciliaton_Image1.png differ
diff --git a/docs/assets/images/ExpensifyHelp_ApprovingReports_01.png b/docs/assets/images/ExpensifyHelp_ApprovingReports_01.png
index a9bc57525a1a..587b7cb1d9d8 100644
Binary files a/docs/assets/images/ExpensifyHelp_ApprovingReports_01.png and b/docs/assets/images/ExpensifyHelp_ApprovingReports_01.png differ
diff --git a/docs/assets/images/ExpensifyHelp_ApprovingReports_02.png b/docs/assets/images/ExpensifyHelp_ApprovingReports_02.png
index 4bd2c5af455b..1376c8ccf71c 100644
Binary files a/docs/assets/images/ExpensifyHelp_ApprovingReports_02.png and b/docs/assets/images/ExpensifyHelp_ApprovingReports_02.png differ
diff --git a/docs/assets/images/ExpensifyHelp_ApprovingReports_03.png b/docs/assets/images/ExpensifyHelp_ApprovingReports_03.png
index f5318cd5272a..3bf84342edf6 100644
Binary files a/docs/assets/images/ExpensifyHelp_ApprovingReports_03.png and b/docs/assets/images/ExpensifyHelp_ApprovingReports_03.png differ
diff --git a/docs/assets/images/ExpensifyHelp_CardSettings.png b/docs/assets/images/ExpensifyHelp_CardSettings.png
index c10a3d1cbc39..8339bc41ab7f 100644
Binary files a/docs/assets/images/ExpensifyHelp_CardSettings.png and b/docs/assets/images/ExpensifyHelp_CardSettings.png differ
diff --git a/docs/assets/images/ExpensifyHelp_ExpenseRules_01.png b/docs/assets/images/ExpensifyHelp_ExpenseRules_01.png
index 7a6c3c1b3a13..ad71c304a06f 100644
Binary files a/docs/assets/images/ExpensifyHelp_ExpenseRules_01.png and b/docs/assets/images/ExpensifyHelp_ExpenseRules_01.png differ
diff --git a/docs/assets/images/ExpensifyHelp_ExpenseRules_02.png b/docs/assets/images/ExpensifyHelp_ExpenseRules_02.png
index 28c6a7689b77..58d448f4c1f4 100644
Binary files a/docs/assets/images/ExpensifyHelp_ExpenseRules_02.png and b/docs/assets/images/ExpensifyHelp_ExpenseRules_02.png differ
diff --git a/docs/assets/images/ExpensifyHelp_Lyft_01.png b/docs/assets/images/ExpensifyHelp_Lyft_01.png
index 35959779ec09..15c21c750d1d 100644
Binary files a/docs/assets/images/ExpensifyHelp_Lyft_01.png and b/docs/assets/images/ExpensifyHelp_Lyft_01.png differ
diff --git a/docs/assets/images/ExpensifyHelp_SettlementExpanded.png b/docs/assets/images/ExpensifyHelp_SettlementExpanded.png
index 8672c8639202..8b0693c59a40 100644
Binary files a/docs/assets/images/ExpensifyHelp_SettlementExpanded.png and b/docs/assets/images/ExpensifyHelp_SettlementExpanded.png differ
diff --git a/docs/assets/images/ExpensifyHelp_SettlementExport.png b/docs/assets/images/ExpensifyHelp_SettlementExport.png
index b8c9a36220d4..de2a52495576 100644
Binary files a/docs/assets/images/ExpensifyHelp_SettlementExport.png and b/docs/assets/images/ExpensifyHelp_SettlementExport.png differ
diff --git a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_1.png b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_1.png
index d4e73beb16b3..988aa216b59c 100644
Binary files a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_1.png and b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_1.png differ
diff --git a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_2.png b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_2.png
index 45956a586d98..3b441e9cdf1a 100644
Binary files a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_2.png and b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_2.png differ
diff --git a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_3.png b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_3.png
index 32aae12d3687..d1ff39eb22f6 100644
Binary files a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_3.png and b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_3.png differ
diff --git a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_4.png b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_4.png
index ccd9335025bf..316d3f5aca6f 100644
Binary files a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_4.png and b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_4.png differ
diff --git a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_5.png b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_5.png
index 5363935f0ab5..a19880d950fd 100644
Binary files a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_5.png and b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_5.png differ
diff --git a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_6.png b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_6.png
index 739446de8383..af7f3421336e 100644
Binary files a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_6.png and b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_6.png differ
diff --git a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_7.png b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_7.png
index 21a1d3416858..260558881327 100644
Binary files a/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_7.png and b/docs/assets/images/ManagingEmployeesAndReports_ApprovalWorkflows_7.png differ
diff --git a/docs/assets/images/accounting.svg b/docs/assets/images/accounting.svg
index 4398e9573747..bacc7ae21e68 100644
--- a/docs/assets/images/accounting.svg
+++ b/docs/assets/images/accounting.svg
@@ -1,68 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/add-australian-deposit-only-account-modal.png b/docs/assets/images/add-australian-deposit-only-account-modal.png
index 1196a57c8f8f..86fd488fa947 100644
Binary files a/docs/assets/images/add-australian-deposit-only-account-modal.png and b/docs/assets/images/add-australian-deposit-only-account-modal.png differ
diff --git a/docs/assets/images/add-australian-deposit-only-account.png b/docs/assets/images/add-australian-deposit-only-account.png
index 4cea4fb11757..d9593f9958af 100644
Binary files a/docs/assets/images/add-australian-deposit-only-account.png and b/docs/assets/images/add-australian-deposit-only-account.png differ
diff --git a/docs/assets/images/add-vba-australian-account-modal.png b/docs/assets/images/add-vba-australian-account-modal.png
index ee624eca3814..fd02919f1586 100644
Binary files a/docs/assets/images/add-vba-australian-account-modal.png and b/docs/assets/images/add-vba-australian-account-modal.png differ
diff --git a/docs/assets/images/add-vba-australian-account.png b/docs/assets/images/add-vba-australian-account.png
index f064225e176a..dbe06801de62 100644
Binary files a/docs/assets/images/add-vba-australian-account.png and b/docs/assets/images/add-vba-australian-account.png differ
diff --git a/docs/assets/images/arrow-right.svg b/docs/assets/images/arrow-right.svg
index 01e94332393c..2565efbf30a5 100644
--- a/docs/assets/images/arrow-right.svg
+++ b/docs/assets/images/arrow-right.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/arrow-up.svg b/docs/assets/images/arrow-up.svg
index 9f609925d910..844ef49314e4 100644
--- a/docs/assets/images/arrow-up.svg
+++ b/docs/assets/images/arrow-up.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/back-left.svg b/docs/assets/images/back-left.svg
index 071cd22b1644..e6ea47be3da5 100644
--- a/docs/assets/images/back-left.svg
+++ b/docs/assets/images/back-left.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/bank-card.svg b/docs/assets/images/bank-card.svg
index 48da9af0d986..051d028d4af2 100644
--- a/docs/assets/images/bank-card.svg
+++ b/docs/assets/images/bank-card.svg
@@ -1,41 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/cancel-reimbursement.png b/docs/assets/images/cancel-reimbursement.png
index 87317d2f60ba..9257cd759214 100644
Binary files a/docs/assets/images/cancel-reimbursement.png and b/docs/assets/images/cancel-reimbursement.png differ
diff --git a/docs/assets/images/circle-hourglass.svg b/docs/assets/images/circle-hourglass.svg
index 5c307db6bb04..68359ab49315 100644
--- a/docs/assets/images/circle-hourglass.svg
+++ b/docs/assets/images/circle-hourglass.svg
@@ -1,9 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/close.svg b/docs/assets/images/close.svg
index 71e4df7ace0c..9b050b1e91c6 100644
--- a/docs/assets/images/close.svg
+++ b/docs/assets/images/close.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/concierge-avatar.svg b/docs/assets/images/concierge-avatar.svg
index d2a7cf31ac98..eb374a9a5a68 100644
--- a/docs/assets/images/concierge-avatar.svg
+++ b/docs/assets/images/concierge-avatar.svg
@@ -1,39 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/delete-australian-bank-account.png b/docs/assets/images/delete-australian-bank-account.png
index 2148973e5a6c..6d2be119f736 100644
Binary files a/docs/assets/images/delete-australian-bank-account.png and b/docs/assets/images/delete-australian-bank-account.png differ
diff --git a/docs/assets/images/down.svg b/docs/assets/images/down.svg
index d0925eeb1336..c47a53f35ea6 100644
--- a/docs/assets/images/down.svg
+++ b/docs/assets/images/down.svg
@@ -1,10 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/envelope-receipt.svg b/docs/assets/images/envelope-receipt.svg
index 40f57cc4ebda..650f4dca9145 100644
--- a/docs/assets/images/envelope-receipt.svg
+++ b/docs/assets/images/envelope-receipt.svg
@@ -1,35 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/expensify-footer-logo--vertical.svg b/docs/assets/images/expensify-footer-logo--vertical.svg
index 58dc05ad2944..9cd5e26cc8f2 100644
--- a/docs/assets/images/expensify-footer-logo--vertical.svg
+++ b/docs/assets/images/expensify-footer-logo--vertical.svg
@@ -1,30 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/expensify-footer-logo.svg b/docs/assets/images/expensify-footer-logo.svg
index e664651b84fd..9e3f837f7365 100644
--- a/docs/assets/images/expensify-footer-logo.svg
+++ b/docs/assets/images/expensify-footer-logo.svg
@@ -1,30 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/expensify-help.svg b/docs/assets/images/expensify-help.svg
index 7aa084e0fc0c..0655b947a27f 100644
--- a/docs/assets/images/expensify-help.svg
+++ b/docs/assets/images/expensify-help.svg
@@ -1,51 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/expensify-logo-round.png b/docs/assets/images/expensify-logo-round.png
index 59d29ed09530..18fa9ba49969 100644
Binary files a/docs/assets/images/expensify-logo-round.png and b/docs/assets/images/expensify-logo-round.png differ
diff --git a/docs/assets/images/gears.svg b/docs/assets/images/gears.svg
index 23621afc8008..a598dbee28d5 100644
--- a/docs/assets/images/gears.svg
+++ b/docs/assets/images/gears.svg
@@ -1,101 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/hand-card.svg b/docs/assets/images/hand-card.svg
index 779e6ff4184c..4c5b7cfcc666 100644
--- a/docs/assets/images/hand-card.svg
+++ b/docs/assets/images/hand-card.svg
@@ -1,19 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/handshake.svg b/docs/assets/images/handshake.svg
index 04872bd3a88b..1a2f9badc781 100644
--- a/docs/assets/images/handshake.svg
+++ b/docs/assets/images/handshake.svg
@@ -1,36 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/insights-chart.png b/docs/assets/images/insights-chart.png
index 4b21b8d70a09..54000c0ee307 100644
Binary files a/docs/assets/images/insights-chart.png and b/docs/assets/images/insights-chart.png differ
diff --git a/docs/assets/images/lightbulb.svg b/docs/assets/images/lightbulb.svg
index 45a889fb9e0c..b15ec9ced77d 100644
--- a/docs/assets/images/lightbulb.svg
+++ b/docs/assets/images/lightbulb.svg
@@ -1,71 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/menu.svg b/docs/assets/images/menu.svg
index 4fc34e918899..6bc8bc8fa8f7 100644
--- a/docs/assets/images/menu.svg
+++ b/docs/assets/images/menu.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/assets/images/moderation-context-menu.png b/docs/assets/images/moderation-context-menu.png
index 55aa17498cf7..e76a09ce8153 100644
Binary files a/docs/assets/images/moderation-context-menu.png and b/docs/assets/images/moderation-context-menu.png differ
diff --git a/docs/assets/images/moderation-flag-page.png b/docs/assets/images/moderation-flag-page.png
index e60e2ccb8776..e28ff940322d 100644
Binary files a/docs/assets/images/moderation-flag-page.png and b/docs/assets/images/moderation-flag-page.png differ
diff --git a/docs/assets/images/moderation-reportee-whisper.png b/docs/assets/images/moderation-reportee-whisper.png
index 9235a262bef5..1b8fa77b20b7 100644
Binary files a/docs/assets/images/moderation-reportee-whisper.png and b/docs/assets/images/moderation-reportee-whisper.png differ
diff --git a/docs/assets/images/moderation-reporter-whisper.png b/docs/assets/images/moderation-reporter-whisper.png
index 881b25268515..68397f838060 100644
Binary files a/docs/assets/images/moderation-reporter-whisper.png and b/docs/assets/images/moderation-reporter-whisper.png differ
diff --git a/docs/assets/images/money-case.svg b/docs/assets/images/money-case.svg
index c1bb49b3ab5a..e40430c9e27b 100644
--- a/docs/assets/images/money-case.svg
+++ b/docs/assets/images/money-case.svg
@@ -1,135 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/money-circle.svg b/docs/assets/images/money-circle.svg
index 645e1a58701a..f17183ff63b6 100644
--- a/docs/assets/images/money-circle.svg
+++ b/docs/assets/images/money-circle.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/money-into-wallet.svg b/docs/assets/images/money-into-wallet.svg
index d6d5b0e7d6e7..06592778bd51 100644
--- a/docs/assets/images/money-into-wallet.svg
+++ b/docs/assets/images/money-into-wallet.svg
@@ -1,32 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/money-receipt.svg b/docs/assets/images/money-receipt.svg
index 379d56727e42..406aaf3c1db7 100644
--- a/docs/assets/images/money-receipt.svg
+++ b/docs/assets/images/money-receipt.svg
@@ -1,34 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/money-wings.svg b/docs/assets/images/money-wings.svg
index c2155080f721..87ffdf28ec4b 100644
--- a/docs/assets/images/money-wings.svg
+++ b/docs/assets/images/money-wings.svg
@@ -1,26 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/monitor.svg b/docs/assets/images/monitor.svg
index 6e2580b4c9e8..c577e6b0db0a 100644
--- a/docs/assets/images/monitor.svg
+++ b/docs/assets/images/monitor.svg
@@ -1,12 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/og-preview-image.png b/docs/assets/images/og-preview-image.png
index db4bfac8a5cb..4914e7283779 100644
Binary files a/docs/assets/images/og-preview-image.png and b/docs/assets/images/og-preview-image.png differ
diff --git a/docs/assets/images/paper-airplane.svg b/docs/assets/images/paper-airplane.svg
index 8daa13bfa38b..152a5d10f21c 100644
--- a/docs/assets/images/paper-airplane.svg
+++ b/docs/assets/images/paper-airplane.svg
@@ -1,113 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/playbook-existing-corporate-card.png b/docs/assets/images/playbook-existing-corporate-card.png
index 5baad14abf7c..9cfbc02e0ab2 100644
Binary files a/docs/assets/images/playbook-existing-corporate-card.png and b/docs/assets/images/playbook-existing-corporate-card.png differ
diff --git a/docs/assets/images/playbook-expense-basics.png b/docs/assets/images/playbook-expense-basics.png
index b0bbd2095415..99c462070405 100644
Binary files a/docs/assets/images/playbook-expense-basics.png and b/docs/assets/images/playbook-expense-basics.png differ
diff --git a/docs/assets/images/playbook-impoort-employees.png b/docs/assets/images/playbook-impoort-employees.png
index 4f4f6f4e50ae..1cb8a11b95fc 100644
Binary files a/docs/assets/images/playbook-impoort-employees.png and b/docs/assets/images/playbook-impoort-employees.png differ
diff --git a/docs/assets/images/playbook-new-bill.png b/docs/assets/images/playbook-new-bill.png
index 8e8a01fe156b..b27d269e862d 100644
Binary files a/docs/assets/images/playbook-new-bill.png and b/docs/assets/images/playbook-new-bill.png differ
diff --git a/docs/assets/images/playbook-scheduled-submit.png b/docs/assets/images/playbook-scheduled-submit.png
index c8c6eb91774c..32919ae0eb06 100644
Binary files a/docs/assets/images/playbook-scheduled-submit.png and b/docs/assets/images/playbook-scheduled-submit.png differ
diff --git a/docs/assets/images/playbook.svg b/docs/assets/images/playbook.svg
index 0088d8f915f1..e0e2a883e636 100644
--- a/docs/assets/images/playbook.svg
+++ b/docs/assets/images/playbook.svg
@@ -1,88 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/reimbursing-default.png b/docs/assets/images/reimbursing-default.png
index 6823fecaba35..58970385f5dd 100644
Binary files a/docs/assets/images/reimbursing-default.png and b/docs/assets/images/reimbursing-default.png differ
diff --git a/docs/assets/images/reimbursing-manual-warning.png b/docs/assets/images/reimbursing-manual-warning.png
index 34ef6bbc8d3c..1f4c6491c5db 100644
Binary files a/docs/assets/images/reimbursing-manual-warning.png and b/docs/assets/images/reimbursing-manual-warning.png differ
diff --git a/docs/assets/images/reimbursing-manual.png b/docs/assets/images/reimbursing-manual.png
index 8d27f71036ca..a4b66546922e 100644
Binary files a/docs/assets/images/reimbursing-manual.png and b/docs/assets/images/reimbursing-manual.png differ
diff --git a/docs/assets/images/reimbursing-reports-dropdown.png b/docs/assets/images/reimbursing-reports-dropdown.png
index 5a3da794c5e9..d56ad6cbf250 100644
Binary files a/docs/assets/images/reimbursing-reports-dropdown.png and b/docs/assets/images/reimbursing-reports-dropdown.png differ
diff --git a/docs/assets/images/search.svg b/docs/assets/images/search.svg
index 9680cc415454..5bd5fc24d858 100644
--- a/docs/assets/images/search.svg
+++ b/docs/assets/images/search.svg
@@ -1,3 +1 @@
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/assets/images/send.svg b/docs/assets/images/send.svg
index f442d9148327..2ac109683395 100644
--- a/docs/assets/images/send.svg
+++ b/docs/assets/images/send.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/settings-new-dot.svg b/docs/assets/images/settings-new-dot.svg
index 13338fc72362..558e7413c295 100644
--- a/docs/assets/images/settings-new-dot.svg
+++ b/docs/assets/images/settings-new-dot.svg
@@ -1,88 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/settings-old-dot.svg b/docs/assets/images/settings-old-dot.svg
index 89302b65c70d..ca5bc04bd0ff 100644
--- a/docs/assets/images/settings-old-dot.svg
+++ b/docs/assets/images/settings-old-dot.svg
@@ -1,187 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/shield.svg b/docs/assets/images/shield.svg
index 252da0321692..3202a532884c 100644
--- a/docs/assets/images/shield.svg
+++ b/docs/assets/images/shield.svg
@@ -1,16 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/social-facebook.svg b/docs/assets/images/social-facebook.svg
index e10f0b21b4dc..0cf2317839f0 100644
--- a/docs/assets/images/social-facebook.svg
+++ b/docs/assets/images/social-facebook.svg
@@ -1,7 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/social-instagram.svg b/docs/assets/images/social-instagram.svg
index 848a8563403e..d78d50d65aa3 100644
--- a/docs/assets/images/social-instagram.svg
+++ b/docs/assets/images/social-instagram.svg
@@ -1,17 +1 @@
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/social-linkedin.svg b/docs/assets/images/social-linkedin.svg
index d1715494c23a..ef7ed938540f 100644
--- a/docs/assets/images/social-linkedin.svg
+++ b/docs/assets/images/social-linkedin.svg
@@ -1,8 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/social-podcast.svg b/docs/assets/images/social-podcast.svg
index b3db63124d2a..69c5340a389e 100644
--- a/docs/assets/images/social-podcast.svg
+++ b/docs/assets/images/social-podcast.svg
@@ -1,15 +1 @@
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/social-twitter.svg b/docs/assets/images/social-twitter.svg
index 40465f27185c..cadb5fd7474a 100644
--- a/docs/assets/images/social-twitter.svg
+++ b/docs/assets/images/social-twitter.svg
@@ -1,9 +1 @@
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/social-youtube.svg b/docs/assets/images/social-youtube.svg
index 60cfcd9e4147..cec64f2a7766 100644
--- a/docs/assets/images/social-youtube.svg
+++ b/docs/assets/images/social-youtube.svg
@@ -1,11 +1 @@
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/users.svg b/docs/assets/images/users.svg
index 15f3c0e01de5..ad34f781df52 100644
--- a/docs/assets/images/users.svg
+++ b/docs/assets/images/users.svg
@@ -1,14 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/docs/assets/images/workflow.svg b/docs/assets/images/workflow.svg
index e5eac423cd1d..435e3556a5bf 100644
--- a/docs/assets/images/workflow.svg
+++ b/docs/assets/images/workflow.svg
@@ -1,117 +1 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/index.js b/index.js
index ac6b1e452a4b..2a3de088f934 100644
--- a/index.js
+++ b/index.js
@@ -1,9 +1,8 @@
/**
* @format
*/
-
-import {enableLegacyWebImplementation} from 'react-native-gesture-handler';
import {AppRegistry} from 'react-native';
+import {enableLegacyWebImplementation} from 'react-native-gesture-handler';
import App from './src/App';
import Config from './src/CONFIG';
import additionalAppSetup from './src/setup';
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/Store.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/Store.png
index 35d8a1c3cef2..c848522b0b80 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/Store.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/Store.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@2x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@2x.png
index 2f88e782bfd9..c42e7ac3f925 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@2x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@3x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@3x.png
index cae156c0409f..a1e71e266bee 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@3x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iOS@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad.png
index c4f9c3c467d0..ab723d4719b3 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad@2x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad@2x.png
index f36fe1698c60..a87298744bda 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad@2x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPad@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPadPro.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPadPro.png
index 389e9bf64676..aa2cbc1473ee 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPadPro.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/iPadPro.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x 1.png
index 48f5d96656bf..cae0b7d91800 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x.png
index 48f5d96656bf..f5d6ad425da1 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@3x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@3x.png
index f5ccc2a65c77..e09d8a3d7db6 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@3x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/notification@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings.png
index 6899938f4b2b..114a9a961e36 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x 1.png
index c401dfbb94d6..f20a51d77e05 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x.png
index c401dfbb94d6..fc73dfab1e1f 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@3x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@3x.png
index f43a34acb801..fa9b49aa9b77 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@3x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/settings@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight.png
index 20f25cfb4a76..21021c78a083 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x 1.png
index fb8e5ca9d8cc..c692788c1884 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x.png
index fb8e5ca9d8cc..c692788c1884 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@3x.png b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@3x.png
index b9ac89a69f28..2ac3b654fe66 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@3x.png and b/ios/NewExpensify/Images.xcassets/AppIcon.appiconset/spotlight@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_Store.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_Store.png
index 2647154f2d96..c5426cffe80f 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_Store.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_Store.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp.png
index 2ac48e7baaeb..1486278b3a88 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp@2x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp@2x.png
index 8fe39eeb5d9e..b3e0c7a19150 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadApp@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadPro@2x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadPro@2x.png
index b6e348e6ca32..621562e831f2 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadPro@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPadPro@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x 1.png
index ae9b47105114..3975d1932fcb 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x.png
index ae9b47105114..3975d1932fcb 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x 1.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x 1.png
index e47a76cd08a7..a68d092e932b 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x.png
index e47a76cd08a7..a68d092e932b 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_iPhoneApp@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x 1.png
index 523e6cfff8ae..03666c6795c6 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x.png
index 523e6cfff8ae..03666c6795c6 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@3x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@3x.png
index 8f4f398039c2..8a9f7e8f33d0 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_notification@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings 1.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings 1.png
index 9f18efd8459e..8acce9b73e11 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings 1.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings.png
index 9f18efd8459e..4cbeca376a16 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x 1.png
index edad826a6f40..593f6c0b80e6 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x.png
index edad826a6f40..8b8e901b76ea 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@3x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@3x.png
index 69007e1228d7..f0fcce2013f0 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_settings@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight.png
index 70d926b9a29a..cfb6931918fb 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x 1.png
index d7d5d2d5a6c5..8aeedc372d8a 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x.png
index d7d5d2d5a6c5..8aeedc372d8a 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@3x.png b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@3x.png
index 9ab486c7d734..de088f2cbb4a 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconAdHoc.appiconset/ADHOC_spotlight@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_Store.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_Store.png
index 059d94609dca..8c874e35d5c6 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_Store.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_Store.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad.png
index 6eca3a8f40ac..6faf177e719c 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad@2x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad@2x.png
index dc3830a7bcf6..cf1e53c5bbd7 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPad@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPadPro@2x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPadPro@2x.png
index d97d63d7b46f..d346990c457b 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPadPro@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPadPro@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x 1.png
index dd38161a9b07..384591a8b1cb 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x.png
index dd38161a9b07..384591a8b1cb 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x 1.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x 1.png
index 97ec15762932..4babfe38e762 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x.png
index 97ec15762932..4babfe38e762 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_iPhoneApp@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x 1.png
index 376f4d892acf..28319e37fc83 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x.png
index 376f4d892acf..a168b886a55a 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@3x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@3x.png
index d432d60317da..9557f767292b 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_notification@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings 1.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings 1.png
index dd3aeae3ec96..f656aa833eb9 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings 1.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings.png
index dd3aeae3ec96..d1a3e4aab777 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x 1.png
index f0e93e004e40..435c13e5a593 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x.png
index f0e93e004e40..ec35ac2b1519 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@3x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@3x.png
index 706525192794..95a262ee83dd 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_settings@3x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight.png
index bdda62ab3996..3c4d7c922246 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x 1.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x 1.png
index 03c0e26ce666..ca98e2363033 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x 1.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x 1.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x.png
index 03c0e26ce666..ca98e2363033 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@2x.png differ
diff --git a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@3x.png b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@3x.png
index 1e20ff590d2d..85a707216902 100644
Binary files a/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@3x.png and b/ios/NewExpensify/Images.xcassets/AppIconDev.appiconset/DEV_spotlight@3x.png differ
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index c79b98b0b771..10c7e43c98f1 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.3.90
+ 1.3.93
CFBundleSignature
????
CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.3.90.1
+ 1.3.93.0
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 9dc48ca35174..ad90d11e41f0 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.3.90
+ 1.3.93
CFBundleSignature
????
CFBundleVersion
- 1.3.90.1
+ 1.3.93.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index cb120bca2b88..97143f53b867 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -753,6 +753,8 @@ PODS:
- Firebase/Performance (= 8.8.0)
- React-Core
- RNFBApp
+ - RNFlashList (1.6.1):
+ - React-Core
- RNFS (2.20.0):
- React-Core
- RNGestureHandler (2.12.0):
@@ -925,6 +927,7 @@ DEPENDENCIES:
- "RNFBApp (from `../node_modules/@react-native-firebase/app`)"
- "RNFBCrashlytics (from `../node_modules/@react-native-firebase/crashlytics`)"
- "RNFBPerf (from `../node_modules/@react-native-firebase/perf`)"
+ - "RNFlashList (from `../node_modules/@shopify/flash-list`)"
- RNFS (from `../node_modules/react-native-fs`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- "RNGoogleSignin (from `../node_modules/@react-native-google-signin/google-signin`)"
@@ -1134,6 +1137,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/@react-native-firebase/crashlytics"
RNFBPerf:
:path: "../node_modules/@react-native-firebase/perf"
+ RNFlashList:
+ :path: "../node_modules/@shopify/flash-list"
RNFS:
:path: "../node_modules/react-native-fs"
RNGestureHandler:
@@ -1273,6 +1278,7 @@ SPEC CHECKSUMS:
RNFBApp: 729c0666395b1953198dc4a1ec6deb8fbe1c302e
RNFBCrashlytics: 2061ca863e8e2fa1aae9b12477d7dfa8e88ca0f9
RNFBPerf: 389914cda4000fe0d996a752532a591132cbf3f9
+ RNFlashList: 236646d48f224a034f35baa0242e1b77db063b1e
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: dec4645026e7401a0899f2846d864403478ff6a5
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
diff --git a/jest/setup.js b/jest/setup.js
index 4def7d1efad5..38b4b55a68b3 100644
--- a/jest/setup.js
+++ b/jest/setup.js
@@ -1,7 +1,8 @@
-import 'setimmediate';
+import mockClipboard from '@react-native-clipboard/clipboard/jest/clipboard-mock';
+import '@shopify/flash-list/jestSetup';
import 'react-native-gesture-handler/jestSetup';
import * as reanimatedJestUtils from 'react-native-reanimated/src/reanimated2/jestUtils';
-import mockClipboard from '@react-native-clipboard/clipboard/jest/clipboard-mock';
+import 'setimmediate';
import setupMockImages from './setupMockImages';
setupMockImages();
diff --git a/package-lock.json b/package-lock.json
index 6d579a2736a7..690e658fa476 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.90-1",
+ "version": "1.3.93-0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.90-1",
+ "version": "1.3.93-0",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -40,6 +40,7 @@
"@react-navigation/stack": "6.3.16",
"@react-ng/bounds-observer": "^0.2.1",
"@rnmapbox/maps": "^10.0.11",
+ "@shopify/flash-list": "^1.6.1",
"@types/node": "^18.14.0",
"@ua/react-native-airship": "^15.2.6",
"awesome-phonenumber": "^5.4.0",
@@ -50,7 +51,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#bdbdf44825658500ba581d3e86237d7b8996cc2e",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#2adc24c4e889b3a15f199a6b273e343c7d9cff78",
"fbjs": "^3.0.2",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
@@ -135,6 +136,7 @@
"@babel/preset-react": "^7.10.4",
"@babel/preset-typescript": "^7.21.5",
"@babel/runtime": "^7.20.0",
+ "@dword-design/eslint-plugin-import-alias": "^4.0.8",
"@electron/notarize": "^1.2.3",
"@jest/globals": "^29.5.0",
"@octokit/core": "4.0.4",
@@ -154,6 +156,7 @@
"@svgr/webpack": "^6.0.0",
"@testing-library/jest-native": "5.4.1",
"@testing-library/react-native": "11.5.1",
+ "@trivago/prettier-plugin-sort-imports": "^4.2.0",
"@types/concurrently": "^7.0.0",
"@types/jest": "^29.5.2",
"@types/jest-when": "^3.5.2",
@@ -193,7 +196,7 @@
"electron-builder": "24.6.4",
"eslint": "^7.6.0",
"eslint-config-airbnb-typescript": "^17.1.0",
- "eslint-config-expensify": "^2.0.39",
+ "eslint-config-expensify": "^2.0.42",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-jest": "^24.1.0",
"eslint-plugin-jsdoc": "^46.2.6",
@@ -383,11 +386,11 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
- "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dependencies": {
- "@babel/highlight": "^7.22.10",
+ "@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
},
"engines": {
@@ -440,11 +443,11 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
- "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dependencies": {
- "@babel/types": "^7.22.10",
+ "@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -604,20 +607,20 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
- "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
- "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dependencies": {
- "@babel/template": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
@@ -768,9 +771,9 @@
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"engines": {
"node": ">=6.9.0"
}
@@ -811,11 +814,11 @@
}
},
"node_modules/@babel/highlight": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
- "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
@@ -824,9 +827,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.22.11",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz",
- "integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -2552,31 +2555,31 @@
"integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA=="
},
"node_modules/@babel/template": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
- "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dependencies": {
- "@babel/code-frame": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.22.11",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz",
- "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dependencies": {
- "@babel/code-frame": "^7.22.10",
- "@babel/generator": "^7.22.10",
- "@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-function-name": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.22.11",
- "@babel/types": "^7.22.11",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@@ -2585,12 +2588,12 @@
}
},
"node_modules/@babel/types": {
- "version": "7.22.11",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz",
- "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dependencies": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -2939,6 +2942,63 @@
"node": ">=10.0.0"
}
},
+ "node_modules/@dword-design/dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@dword-design/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha512-OFmAmzKiDUh9m7WRMYcoEOPI7b5tS5hdqQmtKDwF+ZssVJv8a+GHo9VOtFsmlw3h8Roh/9QzFWIsjSFZyQUMdg==",
+ "dev": true,
+ "dependencies": {
+ "babel-plugin-add-module-exports": "^1.0.2"
+ }
+ },
+ "node_modules/@dword-design/endent": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@dword-design/endent/-/endent-1.4.1.tgz",
+ "integrity": "sha512-e2sCTzth5kyRdM0o+yEb5wBVzUdJL8Y6HblRGRV0Bif0knf1ZjRLhUjdCrqM+Muirb68X/xJzgdRDJVmLqgXGA==",
+ "dev": true,
+ "dependencies": {
+ "@dword-design/dedent": "^0.7.0",
+ "fast-json-parse": "^1.0.3",
+ "objectorarray": "^1.0.3"
+ }
+ },
+ "node_modules/@dword-design/eslint-plugin-import-alias": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@dword-design/eslint-plugin-import-alias/-/eslint-plugin-import-alias-4.0.8.tgz",
+ "integrity": "sha512-u20BC0eJ6MHhGen+lG38nf/dvlQI7g1GdXLZbgJfOeGT+GKYey7SVTdotY0X4iKWFGGqElkW0bbOuF07T90VOA==",
+ "dev": true,
+ "dependencies": {
+ "@babel/core": "^7.10.2",
+ "@dword-design/functions": "^5.0.22",
+ "babel-plugin-module-resolver": "^5.0.0",
+ "deepmerge": "^4.3.1",
+ "jiti": "^1.18.2"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/dword-design"
+ }
+ },
+ "node_modules/@dword-design/functions": {
+ "version": "5.0.26",
+ "resolved": "https://registry.npmjs.org/@dword-design/functions/-/functions-5.0.26.tgz",
+ "integrity": "sha512-7MxBcG1zP42LR+45kdRvb+P56u48INNKSolGsdmYMFd367btOP/BLHHHTVU1M+uI3KmH7o2J/oasEPtYquravw==",
+ "dev": true,
+ "dependencies": {
+ "@dword-design/endent": "^1.0.0",
+ "delay": "^5.0.0",
+ "lodash": "^4.17.15",
+ "tinycolor2": "^1.4.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/dword-design"
+ }
+ },
"node_modules/@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
@@ -9133,6 +9193,34 @@
"version": "1.14.1",
"license": "0BSD"
},
+ "node_modules/@shopify/flash-list": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.1.tgz",
+ "integrity": "sha512-SlBlpP7+zol6D1SKaf402aS30Qgwdjwb8/Qn2CupYwXnTcu2l8TiXB766vcsIvKTqUO7ELfQnCwCq8NXx55FsQ==",
+ "dependencies": {
+ "recyclerlistview": "4.2.0",
+ "tslib": "2.4.0"
+ },
+ "peerDependencies": {
+ "@babel/runtime": "*",
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/@shopify/flash-list/node_modules/recyclerlistview": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/recyclerlistview/-/recyclerlistview-4.2.0.tgz",
+ "integrity": "sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A==",
+ "dependencies": {
+ "lodash.debounce": "4.0.8",
+ "prop-types": "15.8.1",
+ "ts-object-utils": "0.0.5"
+ },
+ "peerDependencies": {
+ "react": ">= 15.2.1",
+ "react-native": ">= 0.30.0"
+ }
+ },
"node_modules/@sideway/address": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
@@ -19057,6 +19145,65 @@
"node": ">= 10"
}
},
+ "node_modules/@trivago/prettier-plugin-sort-imports": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.2.1.tgz",
+ "integrity": "sha512-iuy2MPVURGdxILTchHr15VAioItuYBejKfcTmQFlxIuqA7jeaT6ngr5aUIG6S6U096d6a6lJCgaOwlRrPLlOPg==",
+ "dev": true,
+ "dependencies": {
+ "@babel/generator": "7.17.7",
+ "@babel/parser": "^7.20.5",
+ "@babel/traverse": "7.23.2",
+ "@babel/types": "7.17.0",
+ "javascript-natural-sort": "0.7.1",
+ "lodash": "^4.17.21"
+ },
+ "peerDependencies": {
+ "@vue/compiler-sfc": "3.x",
+ "prettier": "2.x - 3.x"
+ },
+ "peerDependenciesMeta": {
+ "@vue/compiler-sfc": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/generator": {
+ "version": "7.17.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz",
+ "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==",
+ "dev": true,
+ "dependencies": {
+ "@babel/types": "^7.17.0",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/@babel/types": {
+ "version": "7.17.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
+ "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
+ "dev": true,
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.16.7",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@trivago/prettier-plugin-sort-imports/node_modules/source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -21052,8 +21199,9 @@
}
},
"node_modules/@xmldom/xmldom": {
- "version": "0.7.5",
- "license": "MIT",
+ "version": "0.7.13",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz",
+ "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==",
"engines": {
"node": ">=10.0.0"
}
@@ -22652,6 +22800,12 @@
"babel-runtime": "^6.22.0"
}
},
+ "node_modules/babel-plugin-add-module-exports": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.4.tgz",
+ "integrity": "sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg==",
+ "dev": true
+ },
"node_modules/babel-plugin-add-react-displayname": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz",
@@ -26894,6 +27048,18 @@
"rimraf": "bin.js"
}
},
+ "node_modules/delay": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz",
+ "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -28375,9 +28541,9 @@
}
},
"node_modules/eslint-config-expensify": {
- "version": "2.0.39",
- "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.39.tgz",
- "integrity": "sha512-DIxR3k99ZIDPE2NK+WLLRWpoDq06gTXdY8XZg9Etd1UqZ7fXm/Yz3/QkTxu7CH7UaXbCH3P4PTo023ULQGKOSw==",
+ "version": "2.0.42",
+ "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.42.tgz",
+ "integrity": "sha512-TNwbfIGjOp4EjT6HKEpp10mr6dkBNCNMTeMmpuQyS0Nqv1tRGJltoU3GFmUHJywrLkEmu21iC0NNMmoJ1XzmLg==",
"dev": true,
"dependencies": {
"@lwc/eslint-plugin-lwc": "^0.11.0",
@@ -30189,8 +30355,8 @@
},
"node_modules/expensify-common": {
"version": "1.0.0",
- "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#bdbdf44825658500ba581d3e86237d7b8996cc2e",
- "integrity": "sha512-/kXD/18YQJY/iWB5MOSN0ixB1mpxUA+NXEYgKjac1tJd+DoY3K6+bDeu++Qfqg26LCNfvjTkjkDGZVdGsJQ7Hw==",
+ "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#2adc24c4e889b3a15f199a6b273e343c7d9cff78",
+ "integrity": "sha512-O7XTAfJoCHiFof+X5oFcCgAZAVVJbdIZ+ANA3WBlvabxcPqN0c+dGxIroV8HlRBbTNAkD3CoDVoF61YBUOxCUg==",
"license": "MIT",
"dependencies": {
"classnames": "2.3.1",
@@ -36915,6 +37081,15 @@
"node": ">=8"
}
},
+ "node_modules/jiti": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz",
+ "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==",
+ "dev": true,
+ "bin": {
+ "jiti": "bin/jiti.js"
+ }
+ },
"node_modules/joi": {
"version": "17.10.2",
"resolved": "https://registry.npmjs.org/joi/-/joi-17.10.2.tgz",
@@ -49844,6 +50019,12 @@
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==",
"license": "MIT"
},
+ "node_modules/tinycolor2": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
+ "dev": true
+ },
"node_modules/tinyqueue": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz",
@@ -50106,6 +50287,11 @@
"node": ">=6.10"
}
},
+ "node_modules/ts-object-utils": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
+ "integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="
+ },
"node_modules/ts-pnp": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
@@ -53341,11 +53527,11 @@
}
},
"@babel/code-frame": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
- "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
+ "version": "7.22.13",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
+ "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"requires": {
- "@babel/highlight": "^7.22.10",
+ "@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
}
},
@@ -53384,11 +53570,11 @@
}
},
"@babel/generator": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz",
- "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
+ "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"requires": {
- "@babel/types": "^7.22.10",
+ "@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@@ -53513,17 +53699,17 @@
}
},
"@babel/helper-environment-visitor": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz",
- "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q=="
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
+ "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="
},
"@babel/helper-function-name": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz",
- "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
+ "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"requires": {
- "@babel/template": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/template": "^7.22.15",
+ "@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
@@ -53626,9 +53812,9 @@
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw=="
},
"@babel/helper-validator-identifier": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
- "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ=="
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
+ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
},
"@babel/helper-validator-option": {
"version": "7.22.5",
@@ -53657,19 +53843,19 @@
}
},
"@babel/highlight": {
- "version": "7.22.10",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
- "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
+ "version": "7.22.20",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
+ "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"requires": {
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
}
},
"@babel/parser": {
- "version": "7.22.11",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.11.tgz",
- "integrity": "sha512-R5zb8eJIBPJriQtbH/htEQy4k7E2dHWlD2Y2VT07JCzwYZHBxV5ZYtM0UhXSNMT74LyxuM+b1jdL7pSesXbC/g=="
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
+ "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw=="
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
"version": "7.22.5",
@@ -54747,39 +54933,39 @@
}
},
"@babel/template": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz",
- "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==",
+ "version": "7.22.15",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
+ "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"requires": {
- "@babel/code-frame": "^7.22.5",
- "@babel/parser": "^7.22.5",
- "@babel/types": "^7.22.5"
+ "@babel/code-frame": "^7.22.13",
+ "@babel/parser": "^7.22.15",
+ "@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
- "version": "7.22.11",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.11.tgz",
- "integrity": "sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ==",
+ "version": "7.23.2",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
+ "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"requires": {
- "@babel/code-frame": "^7.22.10",
- "@babel/generator": "^7.22.10",
- "@babel/helper-environment-visitor": "^7.22.5",
- "@babel/helper-function-name": "^7.22.5",
+ "@babel/code-frame": "^7.22.13",
+ "@babel/generator": "^7.23.0",
+ "@babel/helper-environment-visitor": "^7.22.20",
+ "@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.22.11",
- "@babel/types": "^7.22.11",
+ "@babel/parser": "^7.23.0",
+ "@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
}
},
"@babel/types": {
- "version": "7.22.11",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.11.tgz",
- "integrity": "sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg==",
+ "version": "7.23.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
+ "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"requires": {
"@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.5",
+ "@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@@ -55046,6 +55232,51 @@
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"dev": true
},
+ "@dword-design/dedent": {
+ "version": "0.7.0",
+ "resolved": "https://registry.npmjs.org/@dword-design/dedent/-/dedent-0.7.0.tgz",
+ "integrity": "sha512-OFmAmzKiDUh9m7WRMYcoEOPI7b5tS5hdqQmtKDwF+ZssVJv8a+GHo9VOtFsmlw3h8Roh/9QzFWIsjSFZyQUMdg==",
+ "dev": true,
+ "requires": {
+ "babel-plugin-add-module-exports": "^1.0.2"
+ }
+ },
+ "@dword-design/endent": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/@dword-design/endent/-/endent-1.4.1.tgz",
+ "integrity": "sha512-e2sCTzth5kyRdM0o+yEb5wBVzUdJL8Y6HblRGRV0Bif0knf1ZjRLhUjdCrqM+Muirb68X/xJzgdRDJVmLqgXGA==",
+ "dev": true,
+ "requires": {
+ "@dword-design/dedent": "^0.7.0",
+ "fast-json-parse": "^1.0.3",
+ "objectorarray": "^1.0.3"
+ }
+ },
+ "@dword-design/eslint-plugin-import-alias": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/@dword-design/eslint-plugin-import-alias/-/eslint-plugin-import-alias-4.0.8.tgz",
+ "integrity": "sha512-u20BC0eJ6MHhGen+lG38nf/dvlQI7g1GdXLZbgJfOeGT+GKYey7SVTdotY0X4iKWFGGqElkW0bbOuF07T90VOA==",
+ "dev": true,
+ "requires": {
+ "@babel/core": "^7.10.2",
+ "@dword-design/functions": "^5.0.22",
+ "babel-plugin-module-resolver": "^5.0.0",
+ "deepmerge": "^4.3.1",
+ "jiti": "^1.18.2"
+ }
+ },
+ "@dword-design/functions": {
+ "version": "5.0.26",
+ "resolved": "https://registry.npmjs.org/@dword-design/functions/-/functions-5.0.26.tgz",
+ "integrity": "sha512-7MxBcG1zP42LR+45kdRvb+P56u48INNKSolGsdmYMFd367btOP/BLHHHTVU1M+uI3KmH7o2J/oasEPtYquravw==",
+ "dev": true,
+ "requires": {
+ "@dword-design/endent": "^1.0.0",
+ "delay": "^5.0.0",
+ "lodash": "^4.17.15",
+ "tinycolor2": "^1.4.1"
+ }
+ },
"@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
@@ -59447,6 +59678,27 @@
}
}
},
+ "@shopify/flash-list": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.6.1.tgz",
+ "integrity": "sha512-SlBlpP7+zol6D1SKaf402aS30Qgwdjwb8/Qn2CupYwXnTcu2l8TiXB766vcsIvKTqUO7ELfQnCwCq8NXx55FsQ==",
+ "requires": {
+ "recyclerlistview": "4.2.0",
+ "tslib": "2.4.0"
+ },
+ "dependencies": {
+ "recyclerlistview": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/recyclerlistview/-/recyclerlistview-4.2.0.tgz",
+ "integrity": "sha512-uuBCi0c+ggqHKwrzPX4Z/mJOzsBbjZEAwGGmlwpD/sD7raXixdAbdJ6BTcAmuWG50Cg4ru9p12M94Njwhr/27A==",
+ "requires": {
+ "lodash.debounce": "4.0.8",
+ "prop-types": "15.8.1",
+ "ts-object-utils": "0.0.5"
+ }
+ }
+ }
+ },
"@sideway/address": {
"version": "4.1.4",
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
@@ -66535,6 +66787,49 @@
"integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==",
"dev": true
},
+ "@trivago/prettier-plugin-sort-imports": {
+ "version": "4.2.1",
+ "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-4.2.1.tgz",
+ "integrity": "sha512-iuy2MPVURGdxILTchHr15VAioItuYBejKfcTmQFlxIuqA7jeaT6ngr5aUIG6S6U096d6a6lJCgaOwlRrPLlOPg==",
+ "dev": true,
+ "requires": {
+ "@babel/generator": "7.17.7",
+ "@babel/parser": "^7.20.5",
+ "@babel/traverse": "7.23.2",
+ "@babel/types": "7.17.0",
+ "javascript-natural-sort": "0.7.1",
+ "lodash": "^4.17.21"
+ },
+ "dependencies": {
+ "@babel/generator": {
+ "version": "7.17.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.7.tgz",
+ "integrity": "sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w==",
+ "dev": true,
+ "requires": {
+ "@babel/types": "^7.17.0",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ }
+ },
+ "@babel/types": {
+ "version": "7.17.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz",
+ "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==",
+ "dev": true,
+ "requires": {
+ "@babel/helper-validator-identifier": "^7.16.7",
+ "to-fast-properties": "^2.0.0"
+ }
+ },
+ "source-map": {
+ "version": "0.5.7",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+ "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==",
+ "dev": true
+ }
+ }
+ },
"@trysound/sax": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz",
@@ -68117,7 +68412,9 @@
}
},
"@xmldom/xmldom": {
- "version": "0.7.5"
+ "version": "0.7.13",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.7.13.tgz",
+ "integrity": "sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g=="
},
"@xtuc/ieee754": {
"version": "1.2.0",
@@ -69272,6 +69569,12 @@
"babel-runtime": "^6.22.0"
}
},
+ "babel-plugin-add-module-exports": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/babel-plugin-add-module-exports/-/babel-plugin-add-module-exports-1.0.4.tgz",
+ "integrity": "sha512-g+8yxHUZ60RcyaUpfNzy56OtWW+x9cyEe9j+CranqLiqbju2yf/Cy6ZtYK40EZxtrdHllzlVZgLmcOUCTlJ7Jg==",
+ "dev": true
+ },
"babel-plugin-add-react-displayname": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/babel-plugin-add-react-displayname/-/babel-plugin-add-react-displayname-0.0.5.tgz",
@@ -72364,6 +72667,12 @@
}
}
},
+ "delay": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz",
+ "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==",
+ "dev": true
+ },
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -73609,9 +73918,9 @@
}
},
"eslint-config-expensify": {
- "version": "2.0.39",
- "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.39.tgz",
- "integrity": "sha512-DIxR3k99ZIDPE2NK+WLLRWpoDq06gTXdY8XZg9Etd1UqZ7fXm/Yz3/QkTxu7CH7UaXbCH3P4PTo023ULQGKOSw==",
+ "version": "2.0.42",
+ "resolved": "https://registry.npmjs.org/eslint-config-expensify/-/eslint-config-expensify-2.0.42.tgz",
+ "integrity": "sha512-TNwbfIGjOp4EjT6HKEpp10mr6dkBNCNMTeMmpuQyS0Nqv1tRGJltoU3GFmUHJywrLkEmu21iC0NNMmoJ1XzmLg==",
"dev": true,
"requires": {
"@lwc/eslint-plugin-lwc": "^0.11.0",
@@ -74774,9 +75083,9 @@
}
},
"expensify-common": {
- "version": "git+ssh://git@github.com/Expensify/expensify-common.git#bdbdf44825658500ba581d3e86237d7b8996cc2e",
- "integrity": "sha512-/kXD/18YQJY/iWB5MOSN0ixB1mpxUA+NXEYgKjac1tJd+DoY3K6+bDeu++Qfqg26LCNfvjTkjkDGZVdGsJQ7Hw==",
- "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#bdbdf44825658500ba581d3e86237d7b8996cc2e",
+ "version": "git+ssh://git@github.com/Expensify/expensify-common.git#2adc24c4e889b3a15f199a6b273e343c7d9cff78",
+ "integrity": "sha512-O7XTAfJoCHiFof+X5oFcCgAZAVVJbdIZ+ANA3WBlvabxcPqN0c+dGxIroV8HlRBbTNAkD3CoDVoF61YBUOxCUg==",
+ "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#2adc24c4e889b3a15f199a6b273e343c7d9cff78",
"requires": {
"classnames": "2.3.1",
"clipboard": "2.0.4",
@@ -79476,6 +79785,12 @@
}
}
},
+ "jiti": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.20.0.tgz",
+ "integrity": "sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==",
+ "dev": true
+ },
"joi": {
"version": "17.10.2",
"resolved": "https://registry.npmjs.org/joi/-/joi-17.10.2.tgz",
@@ -88799,6 +89114,12 @@
"resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz",
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
},
+ "tinycolor2": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
+ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
+ "dev": true
+ },
"tinyqueue": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-2.0.3.tgz",
@@ -88988,6 +89309,11 @@
"integrity": "sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==",
"dev": true
},
+ "ts-object-utils": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
+ "integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="
+ },
"ts-pnp": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
diff --git a/package.json b/package.json
index 0bf706c73edd..a8143fd2a809 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.90-1",
+ "version": "1.3.93-0",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
@@ -87,6 +87,7 @@
"@react-navigation/stack": "6.3.16",
"@react-ng/bounds-observer": "^0.2.1",
"@rnmapbox/maps": "^10.0.11",
+ "@shopify/flash-list": "^1.6.1",
"@types/node": "^18.14.0",
"@ua/react-native-airship": "^15.2.6",
"awesome-phonenumber": "^5.4.0",
@@ -97,7 +98,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#bdbdf44825658500ba581d3e86237d7b8996cc2e",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#2adc24c4e889b3a15f199a6b273e343c7d9cff78",
"fbjs": "^3.0.2",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
@@ -172,6 +173,8 @@
"underscore": "^1.13.1"
},
"devDependencies": {
+ "@dword-design/eslint-plugin-import-alias": "^4.0.8",
+ "@trivago/prettier-plugin-sort-imports": "^4.2.0",
"@actions/core": "1.10.0",
"@actions/github": "5.1.1",
"@babel/core": "^7.20.0",
@@ -240,7 +243,7 @@
"electron-builder": "24.6.4",
"eslint": "^7.6.0",
"eslint-config-airbnb-typescript": "^17.1.0",
- "eslint-config-expensify": "^2.0.39",
+ "eslint-config-expensify": "^2.0.42",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-jest": "^24.1.0",
"eslint-plugin-jsdoc": "^46.2.6",
diff --git a/scripts/shellCheck.sh b/scripts/shellCheck.sh
index 14424b4d9b30..d148958900d4 100755
--- a/scripts/shellCheck.sh
+++ b/scripts/shellCheck.sh
@@ -22,7 +22,13 @@ info
ASYNC_PROCESSES=()
for SHELL_SCRIPT in $SHELL_SCRIPTS; do
- npx shellcheck -e SC1091 "$SHELL_SCRIPT" &
+ if [[ "$CI" == 'true' ]]; then
+ # ShellCheck is installed by default on GitHub Actions ubuntu runners
+ shellcheck -e SC1091 "$SHELL_SCRIPT" &
+ else
+ # Otherwise shellcheck is used via npx
+ npx shellcheck -e SC1091 "$SHELL_SCRIPT" &
+ fi
ASYNC_PROCESSES+=($!)
done
diff --git a/src/App.js b/src/App.js
index 27e8105c2189..bff766c1235f 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,32 +1,32 @@
-import '../wdyr';
+import {PortalProvider} from '@gorhom/portal';
import React from 'react';
import {LogBox} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
-import {SafeAreaProvider} from 'react-native-safe-area-context';
import Onyx from 'react-native-onyx';
-import {PortalProvider} from '@gorhom/portal';
import {PickerStateProvider} from 'react-native-picker-select';
+import {SafeAreaProvider} from 'react-native-safe-area-context';
+import '../wdyr';
+import ComposeProviders from './components/ComposeProviders';
import CustomStatusBar from './components/CustomStatusBar';
import ErrorBoundary from './components/ErrorBoundary';
-import Expensify from './Expensify';
+import HTMLEngineProvider from './components/HTMLEngineProvider';
import {LocaleContextProvider} from './components/LocaleContextProvider';
import OnyxProvider from './components/OnyxProvider';
-import HTMLEngineProvider from './components/HTMLEngineProvider';
import PopoverContextProvider from './components/PopoverProvider';
-import ComposeProviders from './components/ComposeProviders';
import SafeArea from './components/SafeArea';
-import * as Environment from './libs/Environment/Environment';
-import {WindowDimensionsProvider} from './components/withWindowDimensions';
-import {KeyboardStateProvider} from './components/withKeyboardState';
-import ThemeProvider from './styles/themes/ThemeProvider';
-import ThemeStylesProvider from './styles/ThemeStylesProvider';
import {CurrentReportIDContextProvider} from './components/withCurrentReportID';
import {EnvironmentProvider} from './components/withEnvironment';
-import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext';
-import * as Session from './libs/actions/Session';
+import {KeyboardStateProvider} from './components/withKeyboardState';
+import {WindowDimensionsProvider} from './components/withWindowDimensions';
+import Expensify from './Expensify';
import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop';
import OnyxUpdateManager from './libs/actions/OnyxUpdateManager';
+import * as Session from './libs/actions/Session';
+import * as Environment from './libs/Environment/Environment';
+import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsContext';
import {SidebarNavigationContextProvider} from './pages/home/sidebar/SidebarNavigationContext';
+import ThemeProvider from './styles/themes/ThemeProvider';
+import ThemeStylesProvider from './styles/ThemeStylesProvider';
// For easier debugging and development, when we are in web we expose Onyx to the window, so you can more easily set data into Onyx
if (window && Environment.isDevelopment()) {
diff --git a/src/CONFIG.ts b/src/CONFIG.ts
index 8b1dab5b3d71..61e347671269 100644
--- a/src/CONFIG.ts
+++ b/src/CONFIG.ts
@@ -1,8 +1,8 @@
import {Platform} from 'react-native';
import Config, {NativeConfig} from 'react-native-config';
+import CONST from './CONST';
import getPlatform from './libs/getPlatform';
import * as Url from './libs/Url';
-import CONST from './CONST';
// react-native-config doesn't trim whitespace on iOS for some reason so we
// add a trim() call to prevent headaches
diff --git a/src/CONST.ts b/src/CONST.ts
index a6106b88a532..3989d2b5cbff 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -171,6 +171,10 @@ const CONST = {
ERROR: {
TOO_MANY_ATTEMPTS: 'Too many attempts',
},
+ EVENTS_NAME: {
+ OPEN: 'OPEN',
+ EXIT: 'EXIT',
+ },
},
ERROR: {
MISSING_ROUTING_NUMBER: '402 Missing routingNumber',
@@ -254,7 +258,6 @@ const CONST = {
TASKS: 'tasks',
THREADS: 'threads',
CUSTOM_STATUS: 'customStatus',
- NEW_DOT_CATEGORIES: 'newDotCategories',
NEW_DOT_TAGS: 'newDotTags',
NEW_DOT_SAML: 'newDotSAML',
},
@@ -2779,6 +2782,8 @@ const CONST = {
SCROLLING: 'scrolling',
},
+ CHAT_HEADER_LOADER_HEIGHT: 36,
+
HORIZONTAL_SPACER: {
DEFAULT_BORDER_BOTTOM_WIDTH: 1,
DEFAULT_MARGIN_VERTICAL: 8,
@@ -2786,6 +2791,11 @@ const CONST = {
HIDDEN_BORDER_BOTTOM_WIDTH: 0,
},
+ LIST_COMPONENTS: {
+ HEADER: 'header',
+ FOOTER: 'footer',
+ },
+
GLOBAL_NAVIGATION_OPTION: {
HOME: 'home',
CHATS: 'chats',
diff --git a/src/Expensify.js b/src/Expensify.js
index 6010824cf275..b7e3f0f60567 100644
--- a/src/Expensify.js
+++ b/src/Expensify.js
@@ -1,42 +1,41 @@
-import _ from 'underscore';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import React, {useCallback, useState, useEffect, useRef, useLayoutEffect, useMemo} from 'react';
+import React, {useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react';
import {AppState, Linking} from 'react-native';
import Onyx, {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import ConfirmModal from './components/ConfirmModal';
+import DeeplinkWrapper from './components/DeeplinkWrapper';
+import EmojiPicker from './components/EmojiPicker/EmojiPicker';
+import GrowlNotification from './components/GrowlNotification';
+import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
+import SplashScreenHider from './components/SplashScreenHider';
+import UpdateAppModal from './components/UpdateAppModal';
+import withLocalize, {withLocalizePropTypes} from './components/withLocalize';
+import * as DemoActions from './libs/actions/DemoActions';
+import * as EmojiPickerAction from './libs/actions/EmojiPickerAction';
import * as Report from './libs/actions/Report';
-import BootSplash from './libs/BootSplash';
+import * as User from './libs/actions/User';
import * as ActiveClientManager from './libs/ActiveClientManager';
-import ONYXKEYS from './ONYXKEYS';
-import NavigationRoot from './libs/Navigation/NavigationRoot';
-import migrateOnyx from './libs/migrateOnyx';
-import PushNotification from './libs/Notification/PushNotification';
-import UpdateAppModal from './components/UpdateAppModal';
-import Visibility from './libs/Visibility';
-import GrowlNotification from './components/GrowlNotification';
+import BootSplash from './libs/BootSplash';
+import compose from './libs/compose';
import * as Growl from './libs/Growl';
-import StartupTimer from './libs/StartupTimer';
import Log from './libs/Log';
-import ConfirmModal from './components/ConfirmModal';
-import compose from './libs/compose';
-import withLocalize, {withLocalizePropTypes} from './components/withLocalize';
-import * as User from './libs/actions/User';
-import NetworkConnection from './libs/NetworkConnection';
+import migrateOnyx from './libs/migrateOnyx';
import Navigation from './libs/Navigation/Navigation';
-import PopoverReportActionContextMenu from './pages/home/report/ContextMenu/PopoverReportActionContextMenu';
-import * as ReportActionContextMenu from './pages/home/report/ContextMenu/ReportActionContextMenu';
-import SplashScreenHider from './components/SplashScreenHider';
-import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
-import EmojiPicker from './components/EmojiPicker/EmojiPicker';
-import * as EmojiPickerAction from './libs/actions/EmojiPickerAction';
-import * as DemoActions from './libs/actions/DemoActions';
-import DeeplinkWrapper from './components/DeeplinkWrapper';
-
+import NavigationRoot from './libs/Navigation/NavigationRoot';
+import NetworkConnection from './libs/NetworkConnection';
+import PushNotification from './libs/Notification/PushNotification';
+// eslint-disable-next-line no-unused-vars
+import subscribePushNotification from './libs/Notification/PushNotification/subscribePushNotification';
+import StartupTimer from './libs/StartupTimer';
// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
// eslint-disable-next-line no-unused-vars
import UnreadIndicatorUpdater from './libs/UnreadIndicatorUpdater';
-// eslint-disable-next-line no-unused-vars
-import subscribePushNotification from './libs/Notification/PushNotification/subscribePushNotification';
+import Visibility from './libs/Visibility';
+import ONYXKEYS from './ONYXKEYS';
+import PopoverReportActionContextMenu from './pages/home/report/ContextMenu/PopoverReportActionContextMenu';
+import * as ReportActionContextMenu from './pages/home/report/ContextMenu/ReportActionContextMenu';
Onyx.registerLogger(({level, message}) => {
if (level === 'alert') {
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 68b3bd047ad8..9cd43badac6b 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -1,8 +1,8 @@
-import {ValueOf} from 'type-fest';
import {OnyxEntry} from 'react-native-onyx/lib/types';
-import DeepValueOf from './types/utils/DeepValueOf';
-import * as OnyxTypes from './types/onyx';
+import {ValueOf} from 'type-fest';
import CONST from './CONST';
+import * as OnyxTypes from './types/onyx';
+import DeepValueOf from './types/utils/DeepValueOf';
/**
* This is a file containing constants for all the top level keys in our store
@@ -119,6 +119,9 @@ const ONYXKEYS = {
/** Token needed to initialize Plaid link */
PLAID_LINK_TOKEN: 'plaidLinkToken',
+ /** Capture Plaid event */
+ PLAID_CURRENT_EVENT: 'plaidCurrentEvent',
+
/** Token needed to initialize Onfido */
ONFIDO_TOKEN: 'onfidoToken',
@@ -244,7 +247,7 @@ const ONYXKEYS = {
POLICY_RECENTLY_USED_TAGS: 'policyRecentlyUsedTags_',
WORKSPACE_INVITE_MEMBERS_DRAFT: 'workspaceInviteMembersDraft_',
REPORT: 'report_',
- // REPORT_METADATA is a perf optimization used to hold loading states (isLoadingReportActions, isLoadingMoreReportActions).
+ // REPORT_METADATA is a perf optimization used to hold loading states (isLoadingInitialReportActions, isLoadingOlderReportActions, isLoadingNewerReportActions).
// A lot of components are connected to the Report entity and do not care about the actions. Setting the loading state
// directly on the report caused a lot of unnecessary re-renders
REPORT_METADATA: 'reportMetadata_',
@@ -384,15 +387,15 @@ type OnyxValues = {
[ONYXKEYS.COLLECTION.DOWNLOAD]: OnyxTypes.Download;
[ONYXKEYS.COLLECTION.POLICY]: OnyxTypes.Policy;
[ONYXKEYS.COLLECTION.POLICY_CATEGORIES]: OnyxTypes.PolicyCategory;
- [ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTag;
+ [ONYXKEYS.COLLECTION.POLICY_TAGS]: OnyxTypes.PolicyTags;
[ONYXKEYS.COLLECTION.POLICY_MEMBERS]: OnyxTypes.PolicyMember;
[ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES]: OnyxTypes.RecentlyUsedCategories;
- [ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMember;
+ [ONYXKEYS.COLLECTION.DEPRECATED_POLICY_MEMBER_LIST]: OnyxTypes.PolicyMembers;
[ONYXKEYS.COLLECTION.WORKSPACE_INVITE_MEMBERS_DRAFT]: Record;
[ONYXKEYS.COLLECTION.REPORT]: OnyxTypes.Report;
[ONYXKEYS.COLLECTION.REPORT_METADATA]: OnyxTypes.ReportMetadata;
[ONYXKEYS.COLLECTION.REPORT_ACTIONS]: OnyxTypes.ReportActions;
- [ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS]: string;
+ [ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS]: OnyxTypes.ReportActionsDrafts;
[ONYXKEYS.COLLECTION.REPORT_ACTIONS_REACTIONS]: OnyxTypes.ReportActionReactions;
[ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT]: string;
[ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT_NUMBER_OF_LINES]: number;
diff --git a/src/components/AddPaymentMethodMenu.js b/src/components/AddPaymentMethodMenu.js
index 2c3af95a3fad..252c8380b062 100644
--- a/src/components/AddPaymentMethodMenu.js
+++ b/src/components/AddPaymentMethodMenu.js
@@ -1,16 +1,16 @@
-import _ from 'underscore';
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import compose from '@libs/compose';
+import Permissions from '@libs/Permissions';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as Expensicons from './Icon/Expensicons';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import compose from '../libs/compose';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
-import withWindowDimensions from './withWindowDimensions';
-import Permissions from '../libs/Permissions';
import PopoverMenu from './PopoverMenu';
import refPropTypes from './refPropTypes';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
+import withWindowDimensions from './withWindowDimensions';
const propTypes = {
/** Should the component be visible? */
diff --git a/src/components/AddPlaidBankAccount.js b/src/components/AddPlaidBankAccount.js
index dbe7e46ff6aa..f9667807106b 100644
--- a/src/components/AddPlaidBankAccount.js
+++ b/src/components/AddPlaidBankAccount.js
@@ -1,26 +1,26 @@
-import _ from 'underscore';
-import React, {useEffect, useRef, useCallback} from 'react';
-import {ActivityIndicator, View} from 'react-native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useRef} from 'react';
+import {ActivityIndicator, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import Log from '../libs/Log';
-import PlaidLink from './PlaidLink';
-import * as App from '../libs/actions/App';
-import * as BankAccounts from '../libs/actions/BankAccounts';
-import ONYXKEYS from '../ONYXKEYS';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import Log from '@libs/Log';
+import {plaidDataPropTypes} from '@pages/ReimbursementAccount/plaidDataPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as App from '@userActions/App';
+import * as BankAccounts from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import FullPageOfflineBlockingView from './BlockingViews/FullPageOfflineBlockingView';
+import Icon from './Icon';
+import getBankIcon from './Icon/BankIcons';
import Picker from './Picker';
-import {plaidDataPropTypes} from '../pages/ReimbursementAccount/plaidDataPropTypes';
+import PlaidLink from './PlaidLink';
import Text from './Text';
-import getBankIcon from './Icon/BankIcons';
-import Icon from './Icon';
-import FullPageOfflineBlockingView from './BlockingViews/FullPageOfflineBlockingView';
-import CONST from '../CONST';
-import KeyboardShortcut from '../libs/KeyboardShortcut';
-import useLocalize from '../hooks/useLocalize';
-import useNetwork from '../hooks/useNetwork';
const propTypes = {
/** If the user has been throttled from Plaid */
@@ -203,6 +203,7 @@ function AddPlaidBankAccount({
Log.hmmm('[PlaidLink] Error: ', error.message);
}}
onEvent={(event, metadata) => {
+ BankAccounts.setPlaidEvent(event);
// Handle Plaid login errors (will potentially reset plaid token and item depending on the error)
if (event === 'ERROR') {
Log.hmmm('[PlaidLink] Error: ', metadata);
diff --git a/src/components/AddressSearch/CurrentLocationButton.js b/src/components/AddressSearch/CurrentLocationButton.js
index 893ec031ab7f..326b82d31e8f 100644
--- a/src/components/AddressSearch/CurrentLocationButton.js
+++ b/src/components/AddressSearch/CurrentLocationButton.js
@@ -1,14 +1,14 @@
import PropTypes from 'prop-types';
import React from 'react';
import {Text} from 'react-native';
-import colors from '../../styles/colors';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
-import getButtonState from '../../libs/getButtonState';
-import * as StyleUtils from '../../styles/StyleUtils';
-import useLocalize from '../../hooks/useLocalize';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import useLocalize from '@hooks/useLocalize';
+import getButtonState from '@libs/getButtonState';
+import colors from '@styles/colors';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
const propTypes = {
/** Callback that runs when location button is clicked */
diff --git a/src/components/AddressSearch/index.js b/src/components/AddressSearch/index.js
index 3e676b811c16..3e122e029969 100644
--- a/src/components/AddressSearch/index.js
+++ b/src/components/AddressSearch/index.js
@@ -1,26 +1,26 @@
-import _ from 'underscore';
-import React, {useEffect, useMemo, useRef, useState} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import {Keyboard, LogBox, ScrollView, View, Text, ActivityIndicator} from 'react-native';
+import React, {useEffect, useMemo, useRef, useState} from 'react';
+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';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import TextInput from '../TextInput';
-import * as ApiUtils from '../../libs/ApiUtils';
-import * as GooglePlacesUtils from '../../libs/GooglePlacesUtils';
-import getCurrentPosition from '../../libs/getCurrentPosition';
-import CONST from '../../CONST';
-import * as StyleUtils from '../../styles/StyleUtils';
-import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer';
-import variables from '../../styles/variables';
-import FullScreenLoadingIndicator from '../FullscreenLoadingIndicator';
-import LocationErrorMessage from '../LocationErrorMessage';
-import {withNetwork} from '../OnyxProvider';
-import networkPropTypes from '../networkPropTypes';
+import _ from 'underscore';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import LocationErrorMessage from '@components/LocationErrorMessage';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import * as ApiUtils from '@libs/ApiUtils';
+import compose from '@libs/compose';
+import getCurrentPosition from '@libs/getCurrentPosition';
+import * as GooglePlacesUtils from '@libs/GooglePlacesUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import CurrentLocationButton from './CurrentLocationButton';
+import isCurrentTargetInsideContainer from './isCurrentTargetInsideContainer';
// The error that's being thrown below will be ignored until we fork the
// react-native-google-places-autocomplete repo and replace the
@@ -74,6 +74,9 @@ const propTypes = {
/** A description of the location (usually the address) */
description: PropTypes.string,
+ /** The name of the location */
+ name: PropTypes.string,
+
/** Data required by the google auto complete plugin to know where to put the markers on the map */
geometry: PropTypes.shape({
/** Data about the location */
@@ -167,9 +170,10 @@ function AddressSearch(props) {
// amount of data massaging needs to happen for what the parent expects to get from this function.
if (_.size(details)) {
props.onPress({
- address: lodashGet(details, 'description', ''),
+ address: lodashGet(details, 'description'),
lat: lodashGet(details, 'geometry.location.lat', 0),
lng: lodashGet(details, 'geometry.location.lng', 0),
+ name: lodashGet(details, 'name'),
});
}
return;
@@ -220,7 +224,7 @@ function AddressSearch(props) {
const values = {
street: `${streetNumber} ${streetName}`.trim(),
-
+ name: lodashGet(details, 'name', ''),
// Autocomplete returns any additional valid address fragments (e.g. Apt #) as subpremise.
street2: subpremise,
// Make sure country is updated first, since city and state will be reset if the country changes
@@ -382,6 +386,16 @@ function AddressSearch(props) {
/>
}
+ 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}
+
+ );
+ }}
renderHeaderComponent={renderHeaderComponent}
onPress={(data, details) => {
saveLocationDetails(data, details);
@@ -499,15 +513,14 @@ AddressSearch.propTypes = propTypes;
AddressSearch.defaultProps = defaultProps;
AddressSearch.displayName = 'AddressSearch';
-export default compose(
- withNetwork(),
- withLocalize,
-)(
- React.forwardRef((props, ref) => (
-
- )),
-);
+const AddressSearchWithRef = React.forwardRef((props, ref) => (
+
+));
+
+AddressSearchWithRef.displayName = 'AddressSearchWithRef';
+
+export default compose(withNetwork(), withLocalize)(AddressSearchWithRef);
diff --git a/src/components/AmountTextInput.js b/src/components/AmountTextInput.js
index cc2e1e1e872b..5899e68bedb3 100644
--- a/src/components/AmountTextInput.js
+++ b/src/components/AmountTextInput.js
@@ -1,9 +1,9 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import TextInput from './TextInput';
-import styles from '../styles/styles';
-import CONST from '../CONST';
+import React from 'react';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import refPropTypes from './refPropTypes';
+import TextInput from './TextInput';
const propTypes = {
/** Formatted amount in local currency */
@@ -64,10 +64,14 @@ AmountTextInput.propTypes = propTypes;
AmountTextInput.defaultProps = defaultProps;
AmountTextInput.displayName = 'AmountTextInput';
-export default React.forwardRef((props, ref) => (
+const AmountTextInputWithRef = React.forwardRef((props, ref) => (
));
+
+AmountTextInputWithRef.displayName = 'AmountTextInputWithRef';
+
+export default AmountTextInputWithRef;
diff --git a/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js b/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js
index 46576bc62e7a..fd6c3d358a33 100644
--- a/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js
+++ b/src/components/AnchorForAttachmentsOnly/BaseAnchorForAttachmentsOnly.js
@@ -1,16 +1,16 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import {propTypes as anchorForAttachmentsOnlyPropTypes, defaultProps as anchorForAttachmentsOnlyDefaultProps} from './anchorForAttachmentsOnlyPropTypes';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
-import AttachmentView from '../Attachments/AttachmentView';
-import * as Download from '../../libs/actions/Download';
-import fileDownload from '../../libs/fileDownload';
-import addEncryptedAuthTokenToURL from '../../libs/addEncryptedAuthTokenToURL';
-import {ShowContextMenuContext, showContextMenuForReport} from '../ShowContextMenuContext';
-import * as ReportUtils from '../../libs/ReportUtils';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
+import AttachmentView from '@components/Attachments/AttachmentView';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
+import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL';
+import fileDownload from '@libs/fileDownload';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as Download from '@userActions/Download';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps as anchorForAttachmentsOnlyDefaultProps, propTypes as anchorForAttachmentsOnlyPropTypes} from './anchorForAttachmentsOnlyPropTypes';
const propTypes = {
/** Press in handler for the link */
diff --git a/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js b/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js
index a17f0a27ce4d..9452e615d31c 100644
--- a/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js
+++ b/src/components/AnchorForAttachmentsOnly/anchorForAttachmentsOnlyPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import stylePropTypes from '../../styles/stylePropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
const propTypes = {
/** The URL of the attachment */
diff --git a/src/components/AnchorForAttachmentsOnly/index.js b/src/components/AnchorForAttachmentsOnly/index.js
index 1a58aa4b3ae1..1dae62e771ef 100644
--- a/src/components/AnchorForAttachmentsOnly/index.js
+++ b/src/components/AnchorForAttachmentsOnly/index.js
@@ -1,8 +1,8 @@
import React from 'react';
+import ControlSelection from '@libs/ControlSelection';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as anchorForAttachmentsOnlyPropTypes from './anchorForAttachmentsOnlyPropTypes';
import BaseAnchorForAttachmentsOnly from './BaseAnchorForAttachmentsOnly';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import ControlSelection from '../../libs/ControlSelection';
function AnchorForAttachmentsOnly(props) {
return (
diff --git a/src/components/AnchorForAttachmentsOnly/index.native.js b/src/components/AnchorForAttachmentsOnly/index.native.js
index f27aad641186..91e1b864544d 100644
--- a/src/components/AnchorForAttachmentsOnly/index.native.js
+++ b/src/components/AnchorForAttachmentsOnly/index.native.js
@@ -1,7 +1,7 @@
import React from 'react';
+import styles from '@styles/styles';
import * as anchorForAttachmentsOnlyPropTypes from './anchorForAttachmentsOnlyPropTypes';
import BaseAnchorForAttachmentsOnly from './BaseAnchorForAttachmentsOnly';
-import styles from '../../styles/styles';
function AnchorForAttachmentsOnly(props) {
return (
diff --git a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js
index 9cfe9d893d8e..d79faf4dee9c 100644
--- a/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js
+++ b/src/components/AnchorForCommentsOnly/BaseAnchorForCommentsOnly.js
@@ -1,20 +1,20 @@
-import _ from 'underscore';
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useEffect} from 'react';
import {StyleSheet} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
-import Text from '../Text';
-import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction';
-import * as ReportActionContextMenu from '../../pages/home/report/ContextMenu/ReportActionContextMenu';
-import * as ContextMenuActions from '../../pages/home/report/ContextMenu/ContextMenuActions';
-import Tooltip from '../Tooltip';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
+import _ from 'underscore';
+import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as ContextMenuActions from '@pages/home/report/ContextMenu/ContextMenuActions';
+import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import {propTypes as anchorForCommentsOnlyPropTypes} from './anchorForCommentsOnlyPropTypes';
-import CONST from '../../CONST';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
const propTypes = {
/** Press in handler for the link */
diff --git a/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js b/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js
index 10b5a40c853d..6bf1d094497d 100644
--- a/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js
+++ b/src/components/AnchorForCommentsOnly/anchorForCommentsOnlyPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import stylePropTypes from '../../styles/stylePropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
const propTypes = {
/** The URL to open */
diff --git a/src/components/AnchorForCommentsOnly/index.js b/src/components/AnchorForCommentsOnly/index.js
index 6c72621deeea..24a903dca5fa 100644
--- a/src/components/AnchorForCommentsOnly/index.js
+++ b/src/components/AnchorForCommentsOnly/index.js
@@ -1,8 +1,8 @@
import React from 'react';
+import ControlSelection from '@libs/ControlSelection';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes';
import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import ControlSelection from '../../libs/ControlSelection';
function AnchorForCommentsOnly(props) {
return (
diff --git a/src/components/AnchorForCommentsOnly/index.native.js b/src/components/AnchorForCommentsOnly/index.native.js
index 69211b75e855..b9dc74b7ba05 100644
--- a/src/components/AnchorForCommentsOnly/index.native.js
+++ b/src/components/AnchorForCommentsOnly/index.native.js
@@ -1,7 +1,6 @@
import React from 'react';
import {Linking} from 'react-native';
import _ from 'underscore';
-
import * as anchorForCommentsOnlyPropTypes from './anchorForCommentsOnlyPropTypes';
import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly';
diff --git a/src/components/AnimatedStep/AnimatedStepProvider.js b/src/components/AnimatedStep/AnimatedStepProvider.js
index 86d40b5bddeb..eb4797655344 100644
--- a/src/components/AnimatedStep/AnimatedStepProvider.js
+++ b/src/components/AnimatedStep/AnimatedStepProvider.js
@@ -1,7 +1,7 @@
-import React, {useMemo, useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useMemo, useState} from 'react';
+import CONST from '@src/CONST';
import AnimatedStepContext from './AnimatedStepContext';
-import CONST from '../../CONST';
const propTypes = {
children: PropTypes.node.isRequired,
diff --git a/src/components/AnimatedStep/index.js b/src/components/AnimatedStep/index.js
index 5b0dc8bc78fa..e916cbe1b84c 100644
--- a/src/components/AnimatedStep/index.js
+++ b/src/components/AnimatedStep/index.js
@@ -1,9 +1,9 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import * as Animatable from 'react-native-animatable';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import useNativeDriver from '../../libs/useNativeDriver';
+import useNativeDriver from '@libs/useNativeDriver';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Children to wrap in AnimatedStep. */
diff --git a/src/components/AnonymousReportFooter.js b/src/components/AnonymousReportFooter.js
index 43933210dc0b..2dc4159d1627 100644
--- a/src/components/AnonymousReportFooter.js
+++ b/src/components/AnonymousReportFooter.js
@@ -1,14 +1,14 @@
-import React from 'react';
-import {View, Text} from 'react-native';
import PropTypes from 'prop-types';
-import Button from './Button';
+import React from 'react';
+import {Text, View} from 'react-native';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
import AvatarWithDisplayName from './AvatarWithDisplayName';
+import Button from './Button';
import ExpensifyWordmark from './ExpensifyWordmark';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import reportPropTypes from '../pages/reportPropTypes';
-import styles from '../styles/styles';
-import * as Session from '../libs/actions/Session';
import participantPropTypes from './participantPropTypes';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** The report currently being looked at */
diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js
index 71d331b68db0..52484355a242 100644
--- a/src/components/ArchivedReportFooter.js
+++ b/src/components/ArchivedReportFooter.js
@@ -1,19 +1,19 @@
+import _ from 'lodash';
import lodashGet from 'lodash/get';
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import _ from 'lodash';
-import CONST from '../CONST';
+import compose from '@libs/compose';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import Banner from './Banner';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import compose from '../libs/compose';
-import personalDetailsPropType from '../pages/personalDetailsPropType';
-import ONYXKEYS from '../ONYXKEYS';
-import * as ReportUtils from '../libs/ReportUtils';
-import reportPropTypes from '../pages/reportPropTypes';
-import * as ReportActionsUtils from '../libs/ReportActionsUtils';
-import styles from '../styles/styles';
-import * as PersonalDetailsUtils from '../libs/PersonalDetailsUtils';
const propTypes = {
/** The reason this report was archived */
diff --git a/src/components/ArrowKeyFocusManager.js b/src/components/ArrowKeyFocusManager.js
index b8c726e75af6..19dc3a7ac614 100644
--- a/src/components/ArrowKeyFocusManager.js
+++ b/src/components/ArrowKeyFocusManager.js
@@ -1,7 +1,7 @@
-import {Component} from 'react';
import PropTypes from 'prop-types';
-import CONST from '../CONST';
-import KeyboardShortcut from '../libs/KeyboardShortcut';
+import {Component} from 'react';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import CONST from '@src/CONST';
const propTypes = {
/** Children to render. */
diff --git a/src/components/AttachmentModal.js b/src/components/AttachmentModal.js
index 3f85ba8b5ccb..8231dd7c4fe2 100755
--- a/src/components/AttachmentModal.js
+++ b/src/components/AttachmentModal.js
@@ -1,44 +1,44 @@
-import React, {useState, useCallback, useRef, useMemo} from 'react';
-import PropTypes from 'prop-types';
-import {View, Animated, Keyboard} from 'react-native';
import Str from 'expensify-common/lib/str';
-import lodashGet from 'lodash/get';
import lodashExtend from 'lodash/extend';
-import _ from 'underscore';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {Animated, Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../CONST';
-import Modal from './Modal';
-import AttachmentView from './Attachments/AttachmentView';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL';
+import compose from '@libs/compose';
+import fileDownload from '@libs/fileDownload';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import useNativeDriver from '@libs/useNativeDriver';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import * as IOU from '@userActions/IOU';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import AttachmentCarousel from './Attachments/AttachmentCarousel';
-import useLocalize from '../hooks/useLocalize';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import * as FileUtils from '../libs/fileDownload/FileUtils';
-import themeColors from '../styles/themes/default';
-import compose from '../libs/compose';
-import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
+import AttachmentView from './Attachments/AttachmentView';
import Button from './Button';
-import HeaderWithBackButton from './HeaderWithBackButton';
-import fileDownload from '../libs/fileDownload';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
import ConfirmModal from './ConfirmModal';
import HeaderGap from './HeaderGap';
-import SafeAreaConsumer from './SafeAreaConsumer';
-import addEncryptedAuthTokenToURL from '../libs/addEncryptedAuthTokenToURL';
-import reportPropTypes from '../pages/reportPropTypes';
+import HeaderWithBackButton from './HeaderWithBackButton';
import * as Expensicons from './Icon/Expensicons';
-import useWindowDimensions from '../hooks/useWindowDimensions';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
-import useNativeDriver from '../libs/useNativeDriver';
-import * as ReportActionsUtils from '../libs/ReportActionsUtils';
-import * as ReportUtils from '../libs/ReportUtils';
-import ONYXKEYS from '../ONYXKEYS';
-import * as Policy from '../libs/actions/Policy';
-import useNetwork from '../hooks/useNetwork';
-import * as IOU from '../libs/actions/IOU';
+import Modal from './Modal';
+import SafeAreaConsumer from './SafeAreaConsumer';
import transactionPropTypes from './transactionPropTypes';
-import * as TransactionUtils from '../libs/TransactionUtils';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
/**
* Modal render prop component that exposes modal launching triggers that can be used
@@ -123,7 +123,7 @@ function AttachmentModal(props) {
const [source, setSource] = useState(props.source);
const [modalType, setModalType] = useState(CONST.MODAL.MODAL_TYPE.CENTERED_UNSWIPEABLE);
const [isConfirmButtonDisabled, setIsConfirmButtonDisabled] = useState(false);
- const [confirmButtonFadeAnimation] = useState(new Animated.Value(1));
+ const [confirmButtonFadeAnimation] = useState(() => new Animated.Value(1));
const [shouldShowDownloadButton, setShouldShowDownloadButton] = React.useState(true);
const {windowWidth} = useWindowDimensions();
@@ -137,6 +137,10 @@ function AttachmentModal(props) {
const {translate} = useLocalize();
const {isOffline} = useNetwork();
+ useEffect(() => {
+ setFile(props.originalFileName ? {name: props.originalFileName} : undefined);
+ }, [props.originalFileName]);
+
const onCarouselAttachmentChange = props.onCarouselAttachmentChange;
/**
diff --git a/src/components/AttachmentPicker/attachmentPickerPropTypes.js b/src/components/AttachmentPicker/attachmentPickerPropTypes.js
index 3b6fb7d041c5..a3a346f5ea27 100644
--- a/src/components/AttachmentPicker/attachmentPickerPropTypes.js
+++ b/src/components/AttachmentPicker/attachmentPickerPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
const propTypes = {
/**
diff --git a/src/components/AttachmentPicker/index.js b/src/components/AttachmentPicker/index.js
index 9930fa49a909..24024eae6515 100644
--- a/src/components/AttachmentPicker/index.js
+++ b/src/components/AttachmentPicker/index.js
@@ -1,7 +1,7 @@
import React, {useRef} from 'react';
-import CONST from '../../CONST';
-import {propTypes, defaultProps} from './attachmentPickerPropTypes';
-import Visibility from '../../libs/Visibility';
+import Visibility from '@libs/Visibility';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes} from './attachmentPickerPropTypes';
/**
* Returns acceptable FileTypes based on ATTACHMENT_PICKER_TYPE
diff --git a/src/components/AttachmentPicker/index.native.js b/src/components/AttachmentPicker/index.native.js
index 063314a4268c..0e723d4cf048 100644
--- a/src/components/AttachmentPicker/index.native.js
+++ b/src/components/AttachmentPicker/index.native.js
@@ -1,23 +1,23 @@
-import _ from 'underscore';
-import React, {useState, useRef, useCallback, useMemo} from 'react';
+import lodashCompact from 'lodash/compact';
import PropTypes from 'prop-types';
-import {View, Alert} from 'react-native';
-import RNDocumentPicker from 'react-native-document-picker';
+import React, {useCallback, useMemo, useRef, useState} from 'react';
+import {Alert, View} from 'react-native';
import RNFetchBlob from 'react-native-blob-util';
-import lodashCompact from 'lodash/compact';
+import RNDocumentPicker from 'react-native-document-picker';
import {launchImageLibrary} from 'react-native-image-picker';
-import {propTypes as basePropTypes, defaultProps as baseDefaultProps} from './attachmentPickerPropTypes';
-import CONST from '../../CONST';
-import * as FileUtils from '../../libs/fileDownload/FileUtils';
-import * as Expensicons from '../Icon/Expensicons';
+import _ from 'underscore';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import Popover from '@components/Popover';
+import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import {defaultProps as baseDefaultProps, propTypes as basePropTypes} from './attachmentPickerPropTypes';
import launchCamera from './launchCamera';
-import Popover from '../Popover';
-import MenuItem from '../MenuItem';
-import styles from '../../styles/styles';
-import useLocalize from '../../hooks/useLocalize';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import useKeyboardShortcut from '../../hooks/useKeyboardShortcut';
-import useArrowKeyFocusManager from '../../hooks/useArrowKeyFocusManager';
const propTypes = {
...basePropTypes,
diff --git a/src/components/AttachmentPicker/launchCamera.ios.js b/src/components/AttachmentPicker/launchCamera.ios.js
index 7ac3708c5dd3..d6e3518d7188 100644
--- a/src/components/AttachmentPicker/launchCamera.ios.js
+++ b/src/components/AttachmentPicker/launchCamera.ios.js
@@ -1,5 +1,5 @@
-import {PERMISSIONS, request, RESULTS} from 'react-native-permissions';
import {launchCamera} from 'react-native-image-picker';
+import {PERMISSIONS, request, RESULTS} from 'react-native-permissions';
/**
* Launching the camera for iOS involves checking for permissions
diff --git a/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
index 2c698d5c8a61..673bb7c224e2 100644
--- a/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
+++ b/src/components/Attachments/AttachmentCarousel/AttachmentCarouselCellRenderer.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import {View, PixelRatio} from 'react-native';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
-import styles from '../../../styles/styles';
+import React from 'react';
+import {PixelRatio, View} from 'react-native';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import styles from '@styles/styles';
const propTypes = {
/** Cell Container styles */
diff --git a/src/components/Attachments/AttachmentCarousel/CarouselActions.js b/src/components/Attachments/AttachmentCarousel/CarouselActions.js
index 8861039b8501..cf5309222c4e 100644
--- a/src/components/Attachments/AttachmentCarousel/CarouselActions.js
+++ b/src/components/Attachments/AttachmentCarousel/CarouselActions.js
@@ -1,8 +1,8 @@
-import {useEffect} from 'react';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import KeyboardShortcut from '../../../libs/KeyboardShortcut';
-import CONST from '../../../CONST';
+import {useEffect} from 'react';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import CONST from '@src/CONST';
const propTypes = {
/** Callback to cycle through attachments */
diff --git a/src/components/Attachments/AttachmentCarousel/CarouselButtons.js b/src/components/Attachments/AttachmentCarousel/CarouselButtons.js
index d33659fd04ae..9bef889e61a1 100644
--- a/src/components/Attachments/AttachmentCarousel/CarouselButtons.js
+++ b/src/components/Attachments/AttachmentCarousel/CarouselButtons.js
@@ -1,15 +1,15 @@
import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'underscore';
import {View} from 'react-native';
-import * as Expensicons from '../../Icon/Expensicons';
-import Tooltip from '../../Tooltip';
-import Button from '../../Button';
-import styles from '../../../styles/styles';
-import themeColors from '../../../styles/themes/default';
-import * as AttachmentCarouselViewPropTypes from '../propTypes';
-import useLocalize from '../../../hooks/useLocalize';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
+import _ from 'underscore';
+import * as AttachmentCarouselViewPropTypes from '@components/Attachments/propTypes';
+import Button from '@components/Button';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Tooltip from '@components/Tooltip';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
const propTypes = {
/** Where the arrows should be visible */
diff --git a/src/components/Attachments/AttachmentCarousel/CarouselItem.js b/src/components/Attachments/AttachmentCarousel/CarouselItem.js
index 096b6d60d428..2d271aa6d4c4 100644
--- a/src/components/Attachments/AttachmentCarousel/CarouselItem.js
+++ b/src/components/Attachments/AttachmentCarousel/CarouselItem.js
@@ -1,16 +1,16 @@
+import PropTypes from 'prop-types';
import React, {useContext, useState} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import CONST from '../../../CONST';
-import styles from '../../../styles/styles';
-import useLocalize from '../../../hooks/useLocalize';
-import PressableWithoutFeedback from '../../Pressable/PressableWithoutFeedback';
-import Text from '../../Text';
-import Button from '../../Button';
-import AttachmentView from '../AttachmentView';
-import SafeAreaConsumer from '../../SafeAreaConsumer';
-import ReportAttachmentsContext from '../../../pages/home/report/ReportAttachmentsContext';
-import * as AttachmentsPropTypes from '../propTypes';
+import AttachmentView from '@components/Attachments/AttachmentView';
+import * as AttachmentsPropTypes from '@components/Attachments/propTypes';
+import Button from '@components/Button';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import SafeAreaConsumer from '@components/SafeAreaConsumer';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import ReportAttachmentsContext from '@pages/home/report/ReportAttachmentsContext';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Attachment required information such as the source and file name */
@@ -52,7 +52,7 @@ function CarouselItem({item, isFocused, onPress}) {
const {translate} = useLocalize();
const {isAttachmentHidden} = useContext(ReportAttachmentsContext);
// eslint-disable-next-line es/no-nullish-coalescing-operators
- const [isHidden, setIsHidden] = useState(isAttachmentHidden(item.reportActionID) ?? item.hasBeenFlagged);
+ const [isHidden, setIsHidden] = useState(() => isAttachmentHidden(item.reportActionID) ?? item.hasBeenFlagged);
const renderButton = (style) => (
(
+const AttachmentCarouselPagerWithRef = React.forwardRef((props, ref) => (
));
+
+AttachmentCarouselPagerWithRef.displayName = 'AttachmentCarouselPagerWithRef';
+
+export default AttachmentCarouselPagerWithRef;
diff --git a/src/components/Attachments/AttachmentCarousel/attachmentCarouselPropTypes.js b/src/components/Attachments/AttachmentCarousel/attachmentCarouselPropTypes.js
index 81f22f684243..8048773de42c 100644
--- a/src/components/Attachments/AttachmentCarousel/attachmentCarouselPropTypes.js
+++ b/src/components/Attachments/AttachmentCarousel/attachmentCarouselPropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import reportPropTypes from '../../../pages/reportPropTypes';
-import reportActionPropTypes from '../../../pages/home/report/reportActionPropTypes';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
const propTypes = {
/** source is used to determine the starting index in the array of attachments */
diff --git a/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js
index 8420a9e7831b..6f0dd335c2bb 100644
--- a/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js
+++ b/src/components/Attachments/AttachmentCarousel/extractAttachmentsFromReport.js
@@ -1,11 +1,11 @@
import {Parser as HtmlParser} from 'htmlparser2';
-import _ from 'underscore';
import lodashGet from 'lodash/get';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
-import * as TransactionUtils from '../../../libs/TransactionUtils';
-import * as ReceiptUtils from '../../../libs/ReceiptUtils';
-import CONST from '../../../CONST';
-import tryResolveUrlFromApiRoot from '../../../libs/tryResolveUrlFromApiRoot';
+import _ from 'underscore';
+import * as ReceiptUtils from '@libs/ReceiptUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
+import CONST from '@src/CONST';
/**
* Constructs the initial component state from report actions
diff --git a/src/components/Attachments/AttachmentCarousel/index.js b/src/components/Attachments/AttachmentCarousel/index.js
index 00b603cdd7d9..99a23835fd97 100644
--- a/src/components/Attachments/AttachmentCarousel/index.js
+++ b/src/components/Attachments/AttachmentCarousel/index.js
@@ -1,25 +1,25 @@
-import React, {useRef, useCallback, useState, useEffect} from 'react';
-import {View, FlatList, PixelRatio, Keyboard} from 'react-native';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
+import {FlatList, Keyboard, PixelRatio, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import styles from '../../../styles/styles';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import * as Illustrations from '@components/Icon/Illustrations';
+import withLocalize from '@components/withLocalize';
+import withWindowDimensions from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import ONYXKEYS from '@src/ONYXKEYS';
import AttachmentCarouselCellRenderer from './AttachmentCarouselCellRenderer';
+import {defaultProps, propTypes} from './attachmentCarouselPropTypes';
import CarouselActions from './CarouselActions';
-import withWindowDimensions from '../../withWindowDimensions';
import CarouselButtons from './CarouselButtons';
+import CarouselItem from './CarouselItem';
import extractAttachmentsFromReport from './extractAttachmentsFromReport';
-import {propTypes, defaultProps} from './attachmentCarouselPropTypes';
-import ONYXKEYS from '../../../ONYXKEYS';
-import withLocalize from '../../withLocalize';
-import compose from '../../../libs/compose';
import useCarouselArrows from './useCarouselArrows';
-import CarouselItem from './CarouselItem';
-import Navigation from '../../../libs/Navigation/Navigation';
-import BlockingView from '../../BlockingViews/BlockingView';
-import * as Illustrations from '../../Icon/Illustrations';
-import variables from '../../../styles/variables';
-import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
const viewabilityConfig = {
// To facilitate paging through the attachments, we want to consider an item "viewable" when it is
@@ -78,7 +78,7 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, setDownl
* @param {Object} item
* @param {number} index
*/
- const updatePage = useRef(
+ const updatePage = useCallback(
({viewableItems}) => {
Keyboard.dismiss();
@@ -207,7 +207,7 @@ function AttachmentCarousel({report, reportActions, source, onNavigate, setDownl
getItemLayout={getItemLayout}
keyExtractor={(item) => item.source}
viewabilityConfig={viewabilityConfig}
- onViewableItemsChanged={updatePage.current}
+ onViewableItemsChanged={updatePage}
/>
)}
diff --git a/src/components/Attachments/AttachmentCarousel/index.native.js b/src/components/Attachments/AttachmentCarousel/index.native.js
index bcea50698b3b..8c6957c9371a 100644
--- a/src/components/Attachments/AttachmentCarousel/index.native.js
+++ b/src/components/Attachments/AttachmentCarousel/index.native.js
@@ -1,22 +1,22 @@
import React, {useCallback, useEffect, useRef, useState} from 'react';
-import {View, Keyboard, PixelRatio} from 'react-native';
+import {Keyboard, PixelRatio, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import AttachmentCarouselPager from './Pager';
-import styles from '../../../styles/styles';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import * as Illustrations from '@components/Icon/Illustrations';
+import withLocalize from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps, propTypes} from './attachmentCarouselPropTypes';
import CarouselButtons from './CarouselButtons';
-import ONYXKEYS from '../../../ONYXKEYS';
-import {propTypes, defaultProps} from './attachmentCarouselPropTypes';
+import CarouselItem from './CarouselItem';
import extractAttachmentsFromReport from './extractAttachmentsFromReport';
+import AttachmentCarouselPager from './Pager';
import useCarouselArrows from './useCarouselArrows';
-import CarouselItem from './CarouselItem';
-import Navigation from '../../../libs/Navigation/Navigation';
-import BlockingView from '../../BlockingViews/BlockingView';
-import * as Illustrations from '../../Icon/Illustrations';
-import variables from '../../../styles/variables';
-import compose from '../../../libs/compose';
-import withLocalize from '../../withLocalize';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
function AttachmentCarousel({report, reportActions, source, onNavigate, onClose, setDownloadButtonVisibility, translate}) {
const pagerRef = useRef(null);
diff --git a/src/components/Attachments/AttachmentCarousel/useCarouselArrows.js b/src/components/Attachments/AttachmentCarousel/useCarouselArrows.js
index 64c97fa99819..0c55c3ae519d 100644
--- a/src/components/Attachments/AttachmentCarousel/useCarouselArrows.js
+++ b/src/components/Attachments/AttachmentCarousel/useCarouselArrows.js
@@ -1,6 +1,6 @@
import {useCallback, useEffect, useRef, useState} from 'react';
-import CONST from '../../../CONST';
-import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import CONST from '@src/CONST';
function useCarouselArrows() {
const canUseTouchScreen = DeviceCapabilities.canUseTouchScreen();
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js
index 48ac954ced7f..23049915a8d9 100755
--- a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.js
@@ -1,11 +1,11 @@
import React, {memo} from 'react';
-import styles from '../../../../styles/styles';
-import ImageView from '../../../ImageView';
-import withLocalize, {withLocalizePropTypes} from '../../../withLocalize';
-import compose from '../../../../libs/compose';
-import PressableWithoutFeedback from '../../../Pressable/PressableWithoutFeedback';
-import CONST from '../../../../CONST';
-import {attachmentViewImagePropTypes, attachmentViewImageDefaultProps} from './propTypes';
+import ImageView from '@components/ImageView';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import {attachmentViewImageDefaultProps, attachmentViewImagePropTypes} from './propTypes';
const propTypes = {
...attachmentViewImagePropTypes,
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.native.js b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.native.js
index 7334e5391bc1..faf2f21c133d 100755
--- a/src/components/Attachments/AttachmentView/AttachmentViewImage/index.native.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewImage/index.native.js
@@ -1,12 +1,12 @@
import React, {memo} from 'react';
-import styles from '../../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../withLocalize';
-import ImageView from '../../../ImageView';
-import compose from '../../../../libs/compose';
-import PressableWithoutFeedback from '../../../Pressable/PressableWithoutFeedback';
-import CONST from '../../../../CONST';
-import AttachmentCarouselPage from '../../AttachmentCarousel/Pager/AttachmentCarouselPage';
-import {attachmentViewImagePropTypes, attachmentViewImageDefaultProps} from './propTypes';
+import AttachmentCarouselPage from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPage';
+import ImageView from '@components/ImageView';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import {attachmentViewImageDefaultProps, attachmentViewImagePropTypes} from './propTypes';
const propTypes = {
...attachmentViewImagePropTypes,
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewImage/propTypes.js b/src/components/Attachments/AttachmentView/AttachmentViewImage/propTypes.js
index 661b940da207..184d3ae1a367 100644
--- a/src/components/Attachments/AttachmentView/AttachmentViewImage/propTypes.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewImage/propTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import {attachmentViewPropTypes, attachmentViewDefaultProps} from '../propTypes';
+import {attachmentViewDefaultProps, attachmentViewPropTypes} from '@components/Attachments/AttachmentView/propTypes';
const attachmentViewImagePropTypes = {
...attachmentViewPropTypes,
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.js b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.js
index 1d1de83951ee..c3d1423b17c9 100644
--- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.js
@@ -1,6 +1,6 @@
import React, {memo} from 'react';
-import {attachmentViewPdfPropTypes, attachmentViewPdfDefaultProps} from './propTypes';
-import PDFView from '../../../PDFView';
+import PDFView from '@components/PDFView';
+import {attachmentViewPdfDefaultProps, attachmentViewPdfPropTypes} from './propTypes';
function AttachmentViewPdf({file, encryptedSourceUrl, isFocused, onPress, onScaleChanged, onToggleKeyboard, onLoadComplete, errorLabelStyles, style}) {
return (
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js
index fea72a3fe37a..9ab0b45f8c8f 100644
--- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/index.native.js
@@ -1,7 +1,7 @@
import React, {memo, useCallback, useContext, useEffect} from 'react';
-import {attachmentViewPdfPropTypes, attachmentViewPdfDefaultProps} from './propTypes';
-import PDFView from '../../../PDFView';
-import AttachmentCarouselPagerContext from '../../AttachmentCarousel/Pager/AttachmentCarouselPagerContext';
+import AttachmentCarouselPagerContext from '@components/Attachments/AttachmentCarousel/Pager/AttachmentCarouselPagerContext';
+import PDFView from '@components/PDFView';
+import {attachmentViewPdfDefaultProps, attachmentViewPdfPropTypes} from './propTypes';
function AttachmentViewPdf({file, encryptedSourceUrl, isFocused, isUsedInCarousel, onPress, onScaleChanged: onScaleChangedProp, onToggleKeyboard, onLoadComplete, errorLabelStyles, style}) {
const attachmentCarouselPagerContext = useContext(AttachmentCarouselPagerContext);
diff --git a/src/components/Attachments/AttachmentView/AttachmentViewPdf/propTypes.js b/src/components/Attachments/AttachmentView/AttachmentViewPdf/propTypes.js
index 07203cc2fe74..a34010f0ba8b 100644
--- a/src/components/Attachments/AttachmentView/AttachmentViewPdf/propTypes.js
+++ b/src/components/Attachments/AttachmentView/AttachmentViewPdf/propTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import * as AttachmentsPropTypes from '../../propTypes';
-import stylePropTypes from '../../../../styles/stylePropTypes';
+import * as AttachmentsPropTypes from '@components/Attachments/propTypes';
+import stylePropTypes from '@styles/stylePropTypes';
const attachmentViewPdfPropTypes = {
/** File object maybe be instance of File or Object */
diff --git a/src/components/Attachments/AttachmentView/index.js b/src/components/Attachments/AttachmentView/index.js
index 66d7b2fa89d6..98086dcc4a0c 100755
--- a/src/components/Attachments/AttachmentView/index.js
+++ b/src/components/Attachments/AttachmentView/index.js
@@ -1,29 +1,29 @@
-import React, {memo, useState} from 'react';
-import {View, ScrollView, ActivityIndicator} from 'react-native';
-import _ from 'underscore';
-import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
+import React, {memo, useState} from 'react';
+import {ActivityIndicator, ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import styles from '../../../styles/styles';
-import Icon from '../../Icon';
-import * as Expensicons from '../../Icon/Expensicons';
-import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
-import compose from '../../../libs/compose';
-import Text from '../../Text';
-import Tooltip from '../../Tooltip';
-import themeColors from '../../../styles/themes/default';
-import variables from '../../../styles/variables';
+import _ from 'underscore';
+import DistanceEReceipt from '@components/DistanceEReceipt';
+import EReceipt from '@components/EReceipt';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useNetwork from '@hooks/useNetwork';
+import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL';
+import compose from '@libs/compose';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import cursor from '@styles/utilities/cursor';
+import variables from '@styles/variables';
+import ONYXKEYS from '@src/ONYXKEYS';
import AttachmentViewImage from './AttachmentViewImage';
import AttachmentViewPdf from './AttachmentViewPdf';
-import addEncryptedAuthTokenToURL from '../../../libs/addEncryptedAuthTokenToURL';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import {attachmentViewPropTypes, attachmentViewDefaultProps} from './propTypes';
-import * as TransactionUtils from '../../../libs/TransactionUtils';
-import DistanceEReceipt from '../../DistanceEReceipt';
-import useNetwork from '../../../hooks/useNetwork';
-import ONYXKEYS from '../../../ONYXKEYS';
-import EReceipt from '../../EReceipt';
-import cursor from '../../../styles/utilities/cursor';
+import {attachmentViewDefaultProps, attachmentViewPropTypes} from './propTypes';
const propTypes = {
...attachmentViewPropTypes,
diff --git a/src/components/Attachments/AttachmentView/propTypes.js b/src/components/Attachments/AttachmentView/propTypes.js
index 71ae3639b61c..0c7c8814267f 100644
--- a/src/components/Attachments/AttachmentView/propTypes.js
+++ b/src/components/Attachments/AttachmentView/propTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import * as AttachmentsPropTypes from '../propTypes';
+import * as AttachmentsPropTypes from '@components/Attachments/propTypes';
const attachmentViewPropTypes = {
/** Whether source url requires authentication */
diff --git a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
index 40e08d876907..c024b025c80e 100644
--- a/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
+++ b/src/components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions.js
@@ -1,12 +1,12 @@
import React, {useEffect, useRef} from 'react';
-import Animated, {Easing, FadeOutDown, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
// We take FlatList from this package to properly handle the scrolling of AutoCompleteSuggestions in chats since one scroll is nested inside another
import {FlatList} from 'react-native-gesture-handler';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
-import CONST from '../../CONST';
+import Animated, {Easing, FadeOutDown, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import {propTypes} from './autoCompleteSuggestionsPropTypes';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
/**
* @param {Number} numRows
@@ -110,10 +110,14 @@ function BaseAutoCompleteSuggestions(props) {
BaseAutoCompleteSuggestions.propTypes = propTypes;
BaseAutoCompleteSuggestions.displayName = 'BaseAutoCompleteSuggestions';
-export default React.forwardRef((props, ref) => (
+const BaseAutoCompleteSuggestionsWithRef = React.forwardRef((props, ref) => (
));
+
+BaseAutoCompleteSuggestionsWithRef.displayName = 'BaseAutoCompleteSuggestionsWithRef';
+
+export default BaseAutoCompleteSuggestionsWithRef;
diff --git a/src/components/AutoCompleteSuggestions/index.js b/src/components/AutoCompleteSuggestions/index.js
index 9234d04f4507..30654caf5708 100644
--- a/src/components/AutoCompleteSuggestions/index.js
+++ b/src/components/AutoCompleteSuggestions/index.js
@@ -1,11 +1,11 @@
import React from 'react';
-import {View} from 'react-native';
import ReactDOM from 'react-dom';
-import BaseAutoCompleteSuggestions from './BaseAutoCompleteSuggestions';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
+import {View} from 'react-native';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as StyleUtils from '@styles/StyleUtils';
import {propTypes} from './autoCompleteSuggestionsPropTypes';
-import * as StyleUtils from '../../styles/StyleUtils';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
+import BaseAutoCompleteSuggestions from './BaseAutoCompleteSuggestions';
/**
* On the mobile-web platform, when long-pressing on auto-complete suggestions,
diff --git a/src/components/AutoCompleteSuggestions/index.native.js b/src/components/AutoCompleteSuggestions/index.native.js
index f5ff4636f395..439fa45eae78 100644
--- a/src/components/AutoCompleteSuggestions/index.native.js
+++ b/src/components/AutoCompleteSuggestions/index.native.js
@@ -1,7 +1,7 @@
-import React from 'react';
import {Portal} from '@gorhom/portal';
-import BaseAutoCompleteSuggestions from './BaseAutoCompleteSuggestions';
+import React from 'react';
import {propTypes} from './autoCompleteSuggestionsPropTypes';
+import BaseAutoCompleteSuggestions from './BaseAutoCompleteSuggestions';
function AutoCompleteSuggestions({measureParentContainer, ...props}) {
return (
diff --git a/src/components/AutoEmailLink.js b/src/components/AutoEmailLink.js
index 9f39997bce13..eece1a16ca5a 100644
--- a/src/components/AutoEmailLink.js
+++ b/src/components/AutoEmailLink.js
@@ -1,10 +1,10 @@
-import React from 'react';
+import {CONST} from 'expensify-common/lib/CONST';
import PropTypes from 'prop-types';
+import React from 'react';
import _ from 'underscore';
-import {CONST} from 'expensify-common/lib/CONST';
+import styles from '@styles/styles';
import Text from './Text';
import TextLink from './TextLink';
-import styles from '../styles/styles';
const propTypes = {
text: PropTypes.string.isRequired,
diff --git a/src/components/AutoUpdateTime.js b/src/components/AutoUpdateTime.js
index e7d8b133e903..c85f14ed2c29 100644
--- a/src/components/AutoUpdateTime.js
+++ b/src/components/AutoUpdateTime.js
@@ -2,13 +2,13 @@
* Displays the user's local time and updates it every minute.
* The time auto-update logic is extracted to this component to avoid re-rendering a more complex component, e.g. DetailsPage.
*/
-import {View} from 'react-native';
-import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import PropTypes from 'prop-types';
-import styles from '../styles/styles';
-import DateUtils from '../libs/DateUtils';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {View} from 'react-native';
+import DateUtils from '@libs/DateUtils';
+import styles from '@styles/styles';
import Text from './Text';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** Timezone of the user from their personal details */
diff --git a/src/components/Avatar.js b/src/components/Avatar.js
index 4f0eb60eb2e0..546387031643 100644
--- a/src/components/Avatar.js
+++ b/src/components/Avatar.js
@@ -1,17 +1,17 @@
+import PropTypes from 'prop-types';
import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import stylePropTypes from '../styles/stylePropTypes';
+import useNetwork from '@hooks/useNetwork';
+import * as ReportUtils from '@libs/ReportUtils';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import Icon from './Icon';
-import themeColors from '../styles/themes/default';
-import CONST from '../CONST';
-import * as StyleUtils from '../styles/StyleUtils';
import * as Expensicons from './Icon/Expensicons';
import Image from './Image';
-import styles from '../styles/styles';
-import * as ReportUtils from '../libs/ReportUtils';
-import useNetwork from '../hooks/useNetwork';
const propTypes = {
/** Source for the avatar. Can be a URL or an icon. */
diff --git a/src/components/AvatarCropModal/AvatarCropModal.js b/src/components/AvatarCropModal/AvatarCropModal.js
index 10e8a76f756d..c8bd7f6f7bc8 100644
--- a/src/components/AvatarCropModal/AvatarCropModal.js
+++ b/src/components/AvatarCropModal/AvatarCropModal.js
@@ -2,27 +2,27 @@ import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useState} from 'react';
import {ActivityIndicator, Image, View} from 'react-native';
import {GestureHandlerRootView} from 'react-native-gesture-handler';
-import {runOnUI, interpolate, useAnimatedGestureHandler, useSharedValue, useWorkletCallback} from 'react-native-reanimated';
-import CONST from '../../CONST';
-import compose from '../../libs/compose';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import Button from '../Button';
-import HeaderWithBackButton from '../HeaderWithBackButton';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import Modal from '../Modal';
-import Text from '../Text';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
+import {interpolate, runOnUI, useAnimatedGestureHandler, useSharedValue, useWorkletCallback} from 'react-native-reanimated';
+import Button from '@components/Button';
+import HeaderGap from '@components/HeaderGap';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Modal from '@components/Modal';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import cropOrRotateImage from '@libs/cropOrRotateImage';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import ImageCropView from './ImageCropView';
import Slider from './Slider';
-import cropOrRotateImage from '../../libs/cropOrRotateImage';
-import HeaderGap from '../HeaderGap';
-import * as StyleUtils from '../../styles/StyleUtils';
-import Tooltip from '../Tooltip';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import ScreenWrapper from '../ScreenWrapper';
const propTypes = {
/** Link to image for cropping */
diff --git a/src/components/AvatarCropModal/ImageCropView.js b/src/components/AvatarCropModal/ImageCropView.js
index be19109d7379..cb135cc76c69 100644
--- a/src/components/AvatarCropModal/ImageCropView.js
+++ b/src/components/AvatarCropModal/ImageCropView.js
@@ -3,12 +3,12 @@ import React from 'react';
import {View} from 'react-native';
import {PanGestureHandler} from 'react-native-gesture-handler';
import Animated, {interpolate, useAnimatedStyle} from 'react-native-reanimated';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import * as StyleUtils from '../../styles/StyleUtils';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import ControlSelection from '@libs/ControlSelection';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import gestureHandlerPropTypes from './gestureHandlerPropTypes';
-import ControlSelection from '../../libs/ControlSelection';
const propTypes = {
/** Link to image for cropping */
diff --git a/src/components/AvatarCropModal/Slider.js b/src/components/AvatarCropModal/Slider.js
index 573ee781e5f8..4281da1e7b99 100644
--- a/src/components/AvatarCropModal/Slider.js
+++ b/src/components/AvatarCropModal/Slider.js
@@ -3,11 +3,11 @@ import React, {useState} from 'react';
import {View} from 'react-native';
import {PanGestureHandler} from 'react-native-gesture-handler';
import Animated, {useAnimatedStyle} from 'react-native-reanimated';
-import styles from '../../styles/styles';
+import Tooltip from '@components/Tooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import ControlSelection from '@libs/ControlSelection';
+import styles from '@styles/styles';
import gestureHandlerPropTypes from './gestureHandlerPropTypes';
-import ControlSelection from '../../libs/ControlSelection';
-import Tooltip from '../Tooltip';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
const propTypes = {
/** React-native-reanimated lib handler which executes when the user is panning slider */
diff --git a/src/components/AvatarWithDisplayName.js b/src/components/AvatarWithDisplayName.js
index 03ae8f51bfb6..a7647aef5e99 100644
--- a/src/components/AvatarWithDisplayName.js
+++ b/src/components/AvatarWithDisplayName.js
@@ -1,28 +1,28 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import CONST from '../CONST';
-import reportPropTypes from '../pages/reportPropTypes';
-import participantPropTypes from './participantPropTypes';
-import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import SubscriptAvatar from './SubscriptAvatar';
-import * as ReportUtils from '../libs/ReportUtils';
-import MultipleAvatars from './MultipleAvatars';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import DisplayNames from './DisplayNames';
-import compose from '../libs/compose';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import Text from './Text';
-import * as StyleUtils from '../styles/StyleUtils';
+import MultipleAvatars from './MultipleAvatars';
import ParentNavigationSubtitle from './ParentNavigationSubtitle';
+import participantPropTypes from './participantPropTypes';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
-import * as ReportActionsUtils from '../libs/ReportActionsUtils';
+import SubscriptAvatar from './SubscriptAvatar';
+import Text from './Text';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
const propTypes = {
/** The report currently being looked at */
diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js
index 3dd23d9051eb..871d967e23dc 100644
--- a/src/components/AvatarWithImagePicker.js
+++ b/src/components/AvatarWithImagePicker.js
@@ -1,31 +1,31 @@
-import _ from 'underscore';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
+import _ from 'underscore';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
+import getImageResolution from '@libs/fileDownload/getImageResolution';
+import SpinningIndicatorAnimation from '@styles/animation/SpinningIndicatorAnimation';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import AttachmentModal from './AttachmentModal';
+import AttachmentPicker from './AttachmentPicker';
import Avatar from './Avatar';
+import AvatarCropModal from './AvatarCropModal/AvatarCropModal';
+import DotIndicatorMessage from './DotIndicatorMessage';
import Icon from './Icon';
-import PopoverMenu from './PopoverMenu';
import * as Expensicons from './Icon/Expensicons';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import AttachmentPicker from './AttachmentPicker';
-import AvatarCropModal from './AvatarCropModal/AvatarCropModal';
import OfflineWithFeedback from './OfflineWithFeedback';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import variables from '../styles/variables';
-import CONST from '../CONST';
-import SpinningIndicatorAnimation from '../styles/animation/SpinningIndicatorAnimation';
-import Tooltip from './Tooltip/PopoverAnchorTooltip';
-import stylePropTypes from '../styles/stylePropTypes';
-import * as FileUtils from '../libs/fileDownload/FileUtils';
-import getImageResolution from '../libs/fileDownload/getImageResolution';
+import PopoverMenu from './PopoverMenu';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
-import AttachmentModal from './AttachmentModal';
-import DotIndicatorMessage from './DotIndicatorMessage';
-import * as Browser from '../libs/Browser';
+import Tooltip from './Tooltip/PopoverAnchorTooltip';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
import withNavigationFocus from './withNavigationFocus';
-import compose from '../libs/compose';
const propTypes = {
/** Avatar source to display */
diff --git a/src/components/AvatarWithIndicator.js b/src/components/AvatarWithIndicator.js
index 5e7b8d1ee632..c2a8d5346e13 100644
--- a/src/components/AvatarWithIndicator.js
+++ b/src/components/AvatarWithIndicator.js
@@ -1,12 +1,12 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
import Avatar from './Avatar';
-import styles from '../styles/styles';
-import Tooltip from './Tooltip';
-import * as UserUtils from '../libs/UserUtils';
-import Indicator from './Indicator';
import * as Expensicons from './Icon/Expensicons';
+import Indicator from './Indicator';
+import Tooltip from './Tooltip';
const propTypes = {
/** URL for the avatar */
diff --git a/src/components/Badge.js b/src/components/Badge.js
index 942733baff37..0a6b72201655 100644
--- a/src/components/Badge.js
+++ b/src/components/Badge.js
@@ -1,11 +1,11 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import Text from './Text';
-import CONST from '../CONST';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
+import Text from './Text';
const propTypes = {
/** Is Success type */
diff --git a/src/components/Banner.js b/src/components/Banner.js
index 7ff1ab8210dc..df1be45a96c5 100644
--- a/src/components/Banner.js
+++ b/src/components/Banner.js
@@ -1,19 +1,19 @@
-import React, {memo} from 'react';
import PropTypes from 'prop-types';
+import React, {memo} from 'react';
import {View} from 'react-native';
-import compose from '../libs/compose';
+import compose from '@libs/compose';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import Hoverable from './Hoverable';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
+import PressableWithFeedback from './Pressable/PressableWithFeedback';
import RenderHTML from './RenderHTML';
import Text from './Text';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import getButtonState from '../libs/getButtonState';
import Tooltip from './Tooltip';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import PressableWithFeedback from './Pressable/PressableWithFeedback';
-import CONST from '../CONST';
const propTypes = {
/** Text to display in the banner. */
diff --git a/src/components/BaseMiniContextMenuItem.js b/src/components/BaseMiniContextMenuItem.js
index ffbc5ee76d98..b8d7a4a7484b 100644
--- a/src/components/BaseMiniContextMenuItem.js
+++ b/src/components/BaseMiniContextMenuItem.js
@@ -1,15 +1,15 @@
-import {View} from 'react-native';
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import getButtonState from '../libs/getButtonState';
-import variables from '../styles/variables';
-import Tooltip from './Tooltip/PopoverAnchorTooltip';
+import DomUtils from '@libs/DomUtils';
+import getButtonState from '@libs/getButtonState';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
-import ReportActionComposeFocusManager from '../libs/ReportActionComposeFocusManager';
-import DomUtils from '../libs/DomUtils';
+import Tooltip from './Tooltip/PopoverAnchorTooltip';
const propTypes = {
/**
@@ -90,10 +90,14 @@ BaseMiniContextMenuItem.propTypes = propTypes;
BaseMiniContextMenuItem.defaultProps = defaultProps;
BaseMiniContextMenuItem.displayName = 'BaseMiniContextMenuItem';
-export default React.forwardRef((props, ref) => (
+const BaseMiniContextMenuItemWithRef = React.forwardRef((props, ref) => (
));
+
+BaseMiniContextMenuItemWithRef.displayName = 'BaseMiniContextMenuItemWithRef';
+
+export default BaseMiniContextMenuItemWithRef;
diff --git a/src/components/BigNumberPad.js b/src/components/BigNumberPad.js
index 5587808a09fd..ecbde3a5afe6 100644
--- a/src/components/BigNumberPad.js
+++ b/src/components/BigNumberPad.js
@@ -1,12 +1,12 @@
+import PropTypes from 'prop-types';
import React, {useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import ControlSelection from '@libs/ControlSelection';
+import styles from '@styles/styles';
import Button from './Button';
-import ControlSelection from '../libs/ControlSelection';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import useWindowDimensions from '../hooks/useWindowDimensions';
const propTypes = {
/** Callback to inform parent modal with key pressed */
diff --git a/src/components/BlockingViews/BlockingView.js b/src/components/BlockingViews/BlockingView.js
index 5cb342b0fada..14daddea5f9c 100644
--- a/src/components/BlockingViews/BlockingView.js
+++ b/src/components/BlockingViews/BlockingView.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
-import Icon from '../Icon';
-import Text from '../Text';
-import themeColors from '../../styles/themes/default';
-import TextLink from '../TextLink';
-import Navigation from '../../libs/Navigation/Navigation';
-import AutoEmailLink from '../AutoEmailLink';
-import useLocalize from '../../hooks/useLocalize';
+import AutoEmailLink from '@components/AutoEmailLink';
+import Icon from '@components/Icon';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
const propTypes = {
/** Expensicon for the page */
diff --git a/src/components/BlockingViews/FullPageNotFoundView.js b/src/components/BlockingViews/FullPageNotFoundView.js
index a9c4bf63b65e..5232b5eca8dd 100644
--- a/src/components/BlockingViews/FullPageNotFoundView.js
+++ b/src/components/BlockingViews/FullPageNotFoundView.js
@@ -1,14 +1,14 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Illustrations from '@components/Icon/Illustrations';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import ROUTES from '@src/ROUTES';
import BlockingView from './BlockingView';
-import * as Illustrations from '../Icon/Illustrations';
-import HeaderWithBackButton from '../HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import variables from '../../styles/variables';
-import styles from '../../styles/styles';
-import useLocalize from '../../hooks/useLocalize';
-import ROUTES from '../../ROUTES';
const propTypes = {
/** Child elements */
diff --git a/src/components/BlockingViews/FullPageOfflineBlockingView.js b/src/components/BlockingViews/FullPageOfflineBlockingView.js
index 148c7c751bee..5a876ecb8b1c 100644
--- a/src/components/BlockingViews/FullPageOfflineBlockingView.js
+++ b/src/components/BlockingViews/FullPageOfflineBlockingView.js
@@ -1,10 +1,10 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import networkPropTypes from '../networkPropTypes';
-import {withNetwork} from '../OnyxProvider';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import * as Expensicons from '../Icon/Expensicons';
-import compose from '../../libs/compose';
+import React from 'react';
+import * as Expensicons from '@components/Icon/Expensicons';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
import BlockingView from './BlockingView';
const propTypes = {
diff --git a/src/components/Button/index.js b/src/components/Button/index.js
index dc12a4ded5c2..2039157d3f08 100644
--- a/src/components/Button/index.js
+++ b/src/components/Button/index.js
@@ -1,21 +1,21 @@
+import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {ActivityIndicator, View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import Text from '../Text';
-import KeyboardShortcut from '../../libs/KeyboardShortcut';
-import Icon from '../Icon';
-import CONST from '../../CONST';
-import * as StyleUtils from '../../styles/StyleUtils';
-import HapticFeedback from '../../libs/HapticFeedback';
-import withNavigationFallback from '../withNavigationFallback';
-import compose from '../../libs/compose';
-import * as Expensicons from '../Icon/Expensicons';
-import withNavigationFocus from '../withNavigationFocus';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import refPropTypes from '@components/refPropTypes';
+import Text from '@components/Text';
+import withNavigationFallback from '@components/withNavigationFallback';
+import withNavigationFocus from '@components/withNavigationFocus';
+import compose from '@libs/compose';
+import HapticFeedback from '@libs/HapticFeedback';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import validateSubmitShortcut from './validateSubmitShortcut';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
-import refPropTypes from '../refPropTypes';
const propTypes = {
/** Should the press event bubble across multiple instances when Enter key triggers it. */
@@ -301,6 +301,7 @@ class Button extends Component {
this.props.isDisabled && !this.props.danger && !this.props.success ? styles.buttonDisabled : undefined,
this.props.shouldRemoveRightBorderRadius ? styles.noRightBorderRadius : undefined,
this.props.shouldRemoveLeftBorderRadius ? styles.noLeftBorderRadius : undefined,
+ this.props.icon || this.props.shouldShowRightIcon ? styles.alignItemsStretch : undefined,
...this.props.innerStyles,
]}
hoverStyle={[
diff --git a/src/components/ButtonWithDropdownMenu.js b/src/components/ButtonWithDropdownMenu.js
index 04bc3f6fb54a..7c88d9202b78 100644
--- a/src/components/ButtonWithDropdownMenu.js
+++ b/src/components/ButtonWithDropdownMenu.js
@@ -1,16 +1,16 @@
-import React, {useState, useRef, useEffect} from 'react';
import PropTypes from 'prop-types';
+import React, {useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import useWindowDimensions from '../hooks/useWindowDimensions';
-import styles from '../styles/styles';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import Button from './Button';
-import PopoverMenu from './PopoverMenu';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
-import themeColors from '../styles/themes/default';
-import CONST from '../CONST';
-import * as StyleUtils from '../styles/StyleUtils';
+import PopoverMenu from './PopoverMenu';
const propTypes = {
/** Text to display for the menu header */
diff --git a/src/components/CardOverlay.js b/src/components/CardOverlay.js
deleted file mode 100644
index 5a94b48ec9af..000000000000
--- a/src/components/CardOverlay.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react';
-import {View} from 'react-native';
-import styles from '../styles/styles';
-
-function CardOverlay() {
- return ;
-}
-CardOverlay.displayName = 'CardOverlay';
-
-export default CardOverlay;
diff --git a/src/components/CardPreview.js b/src/components/CardPreview.js
index 4f774d67360c..9f59ca140ce5 100644
--- a/src/components/CardPreview.js
+++ b/src/components/CardPreview.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
+import ExpensifyCardImage from '@assets/images/expensify-card.svg';
+import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import ONYXKEYS from '@src/ONYXKEYS';
import Text from './Text';
-import usePrivatePersonalDetails from '../hooks/usePrivatePersonalDetails';
-import ONYXKEYS from '../ONYXKEYS';
-import ExpensifyCardImage from '../../assets/images/expensify-card.svg';
-import variables from '../styles/variables';
const propTypes = {
/** User's private personal details */
diff --git a/src/components/CategoryPicker/categoryPickerPropTypes.js b/src/components/CategoryPicker/categoryPickerPropTypes.js
index 6f2800a5d98f..0bc116bf45cc 100644
--- a/src/components/CategoryPicker/categoryPickerPropTypes.js
+++ b/src/components/CategoryPicker/categoryPickerPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import categoryPropTypes from '../categoryPropTypes';
+import categoryPropTypes from '@components/categoryPropTypes';
const propTypes = {
/** The policyID we are getting categories for */
diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js
index e7f68e7011fc..f3127131b9b2 100644
--- a/src/components/CategoryPicker/index.js
+++ b/src/components/CategoryPicker/index.js
@@ -1,14 +1,14 @@
+import lodashGet from 'lodash/get';
import React, {useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import ONYXKEYS from '../../ONYXKEYS';
-import {propTypes, defaultProps} from './categoryPickerPropTypes';
-import styles from '../../styles/styles';
-import CONST from '../../CONST';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import OptionsSelector from '../OptionsSelector';
-import useLocalize from '../../hooks/useLocalize';
+import OptionsSelector from '@components/OptionsSelector';
+import useLocalize from '@hooks/useLocalize';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps, propTypes} from './categoryPickerPropTypes';
function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedCategories, onSubmit}) {
const {translate} = useLocalize();
diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js
index b4ffd7a6b062..51b9212133a4 100644
--- a/src/components/Checkbox.js
+++ b/src/components/Checkbox.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import stylePropTypes from '../styles/stylePropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
-import * as StyleUtils from '../styles/StyleUtils';
-import CONST from '../CONST';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
import refPropTypes from './refPropTypes';
diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js
index 63c067c93234..4bffadecb733 100644
--- a/src/components/CheckboxWithLabel.js
+++ b/src/components/CheckboxWithLabel.js
@@ -1,13 +1,13 @@
-import React, {useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
import Checkbox from './Checkbox';
-import Text from './Text';
import FormHelpMessage from './FormHelpMessage';
-import variables from '../styles/variables';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
+import Text from './Text';
/**
* Returns an error if the required props are not provided
@@ -85,7 +85,7 @@ const defaultProps = {
function CheckboxWithLabel(props) {
// We need to pick the first value that is strictly a boolean
// https://github.com/Expensify/App/issues/16885#issuecomment-1520846065
- const [isChecked, setIsChecked] = useState(_.find([props.value, props.defaultValue, props.isChecked], (value) => _.isBoolean(value)));
+ const [isChecked, setIsChecked] = useState(() => _.find([props.value, props.defaultValue, props.isChecked], (value) => _.isBoolean(value)));
const toggleCheckbox = () => {
const newState = !isChecked;
@@ -130,10 +130,14 @@ CheckboxWithLabel.propTypes = propTypes;
CheckboxWithLabel.defaultProps = defaultProps;
CheckboxWithLabel.displayName = 'CheckboxWithLabel';
-export default React.forwardRef((props, ref) => (
+const CheckboxWithLabelWithRef = React.forwardRef((props, ref) => (
));
+
+CheckboxWithLabelWithRef.displayName = 'CheckboxWithLabelWithRef';
+
+export default CheckboxWithLabelWithRef;
diff --git a/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js b/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js
index f5bc097d95f7..61a2d6feaa4b 100644
--- a/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js
+++ b/src/components/CheckboxWithTooltip/CheckboxWithTooltipForMobileWebAndNative.js
@@ -1,9 +1,9 @@
import React from 'react';
import {View} from 'react-native';
-import Checkbox from '../Checkbox';
-import {propTypes, defaultProps} from './checkboxWithTooltipPropTypes';
-import Growl from '../../libs/Growl';
-import withWindowDimensions from '../withWindowDimensions';
+import Checkbox from '@components/Checkbox';
+import withWindowDimensions from '@components/withWindowDimensions';
+import Growl from '@libs/Growl';
+import {defaultProps, propTypes} from './checkboxWithTooltipPropTypes';
class CheckboxWithTooltipForMobileWebAndNative extends React.Component {
constructor(props) {
diff --git a/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js b/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js
index 1656fa7a82cc..67588d00ef65 100644
--- a/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js
+++ b/src/components/CheckboxWithTooltip/checkboxWithTooltipPropTypes.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
-import {windowDimensionsPropTypes} from '../withWindowDimensions';
-import CONST from '../../CONST';
-import stylePropTypes from '../../styles/stylePropTypes';
+import {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import stylePropTypes from '@styles/stylePropTypes';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether the checkbox is checked */
diff --git a/src/components/CheckboxWithTooltip/index.js b/src/components/CheckboxWithTooltip/index.js
index 70b1f345fb61..06e4e0412eba 100644
--- a/src/components/CheckboxWithTooltip/index.js
+++ b/src/components/CheckboxWithTooltip/index.js
@@ -1,10 +1,10 @@
import React from 'react';
import {View} from 'react-native';
+import Checkbox from '@components/Checkbox';
+import Tooltip from '@components/Tooltip';
+import withWindowDimensions from '@components/withWindowDimensions';
import CheckboxWithTooltipForMobileWebAndNative from './CheckboxWithTooltipForMobileWebAndNative';
-import Checkbox from '../Checkbox';
-import {propTypes, defaultProps} from './checkboxWithTooltipPropTypes';
-import Tooltip from '../Tooltip';
-import withWindowDimensions from '../withWindowDimensions';
+import {defaultProps, propTypes} from './checkboxWithTooltipPropTypes';
function CheckboxWithTooltip(props) {
if (props.isSmallScreenWidth || props.isMediumScreenWidth) {
diff --git a/src/components/CheckboxWithTooltip/index.native.js b/src/components/CheckboxWithTooltip/index.native.js
index 61d171d1717a..46ce0bbd131e 100644
--- a/src/components/CheckboxWithTooltip/index.native.js
+++ b/src/components/CheckboxWithTooltip/index.native.js
@@ -1,7 +1,7 @@
import React from 'react';
-import {propTypes, defaultProps} from './checkboxWithTooltipPropTypes';
-import withWindowDimensions from '../withWindowDimensions';
+import withWindowDimensions from '@components/withWindowDimensions';
import CheckboxWithTooltipForMobileWebAndNative from './CheckboxWithTooltipForMobileWebAndNative';
+import {defaultProps, propTypes} from './checkboxWithTooltipPropTypes';
function CheckboxWithTooltip(props) {
return (
diff --git a/src/components/CollapsibleSection/Collapsible/index.native.js b/src/components/CollapsibleSection/Collapsible/index.native.js
index 022d2a2a2ff9..9b800304beeb 100644
--- a/src/components/CollapsibleSection/Collapsible/index.native.js
+++ b/src/components/CollapsibleSection/Collapsible/index.native.js
@@ -1,6 +1,6 @@
-import CollapsibleRN from 'react-native-collapsible';
import PropTypes from 'prop-types';
import React from 'react';
+import CollapsibleRN from 'react-native-collapsible';
const propTypes = {
/** Whether the section should start expanded. False by default */
diff --git a/src/components/CollapsibleSection/index.js b/src/components/CollapsibleSection/index.js
index 7009d1905e1d..32d422297ca4 100644
--- a/src/components/CollapsibleSection/index.js
+++ b/src/components/CollapsibleSection/index.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import Collapsible from './Collapsible';
-import Text from '../Text';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
-import CONST from '../../CONST';
const propTypes = {
/** Title of the Collapsible section */
diff --git a/src/components/CommunicationsLink.js b/src/components/CommunicationsLink.js
index c8ca37f51c0f..f09fecea5239 100644
--- a/src/components/CommunicationsLink.js
+++ b/src/components/CommunicationsLink.js
@@ -1,10 +1,10 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
-import * as Expensicons from './Icon/Expensicons';
-import Clipboard from '../libs/Clipboard';
+import Clipboard from '@libs/Clipboard';
+import styles from '@styles/styles';
import ContextMenuItem from './ContextMenuItem';
+import * as Expensicons from './Icon/Expensicons';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
diff --git a/src/components/ComposeProviders.tsx b/src/components/ComposeProviders.tsx
index bff36db25533..2c73719358d8 100644
--- a/src/components/ComposeProviders.tsx
+++ b/src/components/ComposeProviders.tsx
@@ -1,5 +1,5 @@
import React, {ComponentType, ReactNode} from 'react';
-import ChildrenProps from '../types/utils/ChildrenProps';
+import ChildrenProps from '@src/types/utils/ChildrenProps';
type ComposeProvidersProps = ChildrenProps & {
/** Provider components go here */
diff --git a/src/components/Composer/index.android.js b/src/components/Composer/index.android.js
index 1132efa9e50e..aca2a9d06f7a 100644
--- a/src/components/Composer/index.android.js
+++ b/src/components/Composer/index.android.js
@@ -1,10 +1,10 @@
-import React, {useEffect, useCallback, useRef, useMemo} from 'react';
-import {StyleSheet} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef} from 'react';
+import {StyleSheet} from 'react-native';
import _ from 'underscore';
-import RNTextInput from '../RNTextInput';
-import themeColors from '../../styles/themes/default';
-import * as ComposerUtils from '../../libs/ComposerUtils';
+import RNTextInput from '@components/RNTextInput';
+import * as ComposerUtils from '@libs/ComposerUtils';
+import themeColors from '@styles/themes/default';
const propTypes = {
/** Maximum number of lines in the text input */
@@ -131,10 +131,14 @@ function Composer({shouldClear, onClear, isDisabled, maxLines, forwardedRef, isC
Composer.propTypes = propTypes;
Composer.defaultProps = defaultProps;
-export default React.forwardRef((props, ref) => (
+const ComposerWithRef = React.forwardRef((props, ref) => (
));
+
+ComposerWithRef.displayName = 'ComposerWithRef';
+
+export default ComposerWithRef;
diff --git a/src/components/Composer/index.ios.js b/src/components/Composer/index.ios.js
index 0b2c93f6639e..e5dab3756594 100644
--- a/src/components/Composer/index.ios.js
+++ b/src/components/Composer/index.ios.js
@@ -1,10 +1,10 @@
-import React, {useEffect, useRef, useMemo, useCallback} from 'react';
-import {StyleSheet} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef} from 'react';
+import {StyleSheet} from 'react-native';
import _ from 'underscore';
-import RNTextInput from '../RNTextInput';
-import themeColors from '../../styles/themes/default';
-import * as ComposerUtils from '../../libs/ComposerUtils';
+import RNTextInput from '@components/RNTextInput';
+import * as ComposerUtils from '@libs/ComposerUtils';
+import themeColors from '@styles/themes/default';
const propTypes = {
/** If the input should clear, it actually gets intercepted instead of .clear() */
@@ -132,10 +132,14 @@ function Composer({shouldClear, onClear, isDisabled, maxLines, forwardedRef, isC
Composer.propTypes = propTypes;
Composer.defaultProps = defaultProps;
-export default React.forwardRef((props, ref) => (
+const ComposerWithRef = React.forwardRef((props, ref) => (
));
+
+ComposerWithRef.displayName = 'ComposerWithRef';
+
+export default ComposerWithRef;
diff --git a/src/components/Composer/index.js b/src/components/Composer/index.js
index ad7a84cc1828..02042d86a6e0 100755
--- a/src/components/Composer/index.js
+++ b/src/components/Composer/index.js
@@ -1,24 +1,25 @@
-import React, {useState, useRef, useEffect, useCallback, useMemo} from 'react';
-import {StyleSheet, View} from 'react-native';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
import ExpensiMark from 'expensify-common/lib/ExpensiMark';
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {flushSync} from 'react-dom';
-import RNTextInput from '../RNTextInput';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import themeColors from '../../styles/themes/default';
-import updateIsFullComposerAvailable from '../../libs/ComposerUtils/updateIsFullComposerAvailable';
-import * as ComposerUtils from '../../libs/ComposerUtils';
-import * as Browser from '../../libs/Browser';
-import * as StyleUtils from '../../styles/StyleUtils';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
-import compose from '../../libs/compose';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import isEnterWhileComposition from '../../libs/KeyboardShortcut/isEnterWhileComposition';
-import CONST from '../../CONST';
-import withNavigation from '../withNavigation';
-import ReportActionComposeFocusManager from '../../libs/ReportActionComposeFocusManager';
+import {StyleSheet, View} from 'react-native';
+import _ from 'underscore';
+import RNTextInput from '@components/RNTextInput';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withNavigation from '@components/withNavigation';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import * as ComposerUtils from '@libs/ComposerUtils';
+import updateIsFullComposerAvailable from '@libs/ComposerUtils/updateIsFullComposerAvailable';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
const propTypes = {
/** Maximum number of lines in the text input */
@@ -140,6 +141,8 @@ const getNextChars = (str, cursorPos) => {
return substr.substring(0, spaceIndex);
};
+const supportsPassive = DeviceCapabilities.hasPassiveEventListenerSupport();
+
// Enable Markdown parsing.
// On web we like to have the Text Input field always focused so the user can easily type a new chat
function Composer({
@@ -339,7 +342,6 @@ function Composer({
}
textInput.current.scrollTop += event.deltaY;
- event.preventDefault();
event.stopPropagation();
}, []);
@@ -384,7 +386,7 @@ function Composer({
if (textInput.current) {
document.addEventListener('paste', handlePaste);
- textInput.current.addEventListener('wheel', handleWheel);
+ textInput.current.addEventListener('wheel', handleWheel, supportsPassive ? {passive: true} : false);
}
return () => {
@@ -445,6 +447,7 @@ function Composer({
StyleSheet.flatten([style, {outline: 'none'}]),
StyleUtils.getComposeTextAreaPadding(numberOfLines, isComposerFullSize),
+ Browser.isMobileSafari() || Browser.isSafari() ? styles.rtlTextRenderForSafari : {},
],
[style, maxLines, numberOfLines, isComposerFullSize],
);
@@ -489,16 +492,14 @@ function Composer({
Composer.propTypes = propTypes;
Composer.defaultProps = defaultProps;
-export default compose(
- withLocalize,
- withWindowDimensions,
- withNavigation,
-)(
- React.forwardRef((props, ref) => (
-
- )),
-);
+const ComposerWithRef = React.forwardRef((props, ref) => (
+
+));
+
+ComposerWithRef.displayName = 'ComposerWithRef';
+
+export default compose(withLocalize, withWindowDimensions, withNavigation)(ComposerWithRef);
diff --git a/src/components/ConfirmContent.js b/src/components/ConfirmContent.js
index 469efb4f25d9..6142322848d0 100644
--- a/src/components/ConfirmContent.js
+++ b/src/components/ConfirmContent.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import Header from './Header';
-import styles from '../styles/styles';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
import Button from './Button';
-import useLocalize from '../hooks/useLocalize';
-import useNetwork from '../hooks/useNetwork';
-import Text from './Text';
-import variables from '../styles/variables';
+import Header from './Header';
import Icon from './Icon';
+import Text from './Text';
const propTypes = {
/** Title of the modal */
diff --git a/src/components/ConfirmModal.js b/src/components/ConfirmModal.js
index 705a05ec2058..3fe3838c8c81 100755
--- a/src/components/ConfirmModal.js
+++ b/src/components/ConfirmModal.js
@@ -1,9 +1,9 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import CONST from '@src/CONST';
+import ConfirmContent from './ConfirmContent';
import Modal from './Modal';
-import CONST from '../CONST';
import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-import ConfirmContent from './ConfirmContent';
const propTypes = {
/** Title of the modal */
diff --git a/src/components/ConfirmPopover.js b/src/components/ConfirmPopover.js
index 88df6347f850..83001736b471 100644
--- a/src/components/ConfirmPopover.js
+++ b/src/components/ConfirmPopover.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import ConfirmContent from './ConfirmContent';
import Popover from './Popover';
import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-import ConfirmContent from './ConfirmContent';
const propTypes = {
/** Title of the modal */
diff --git a/src/components/ConfirmationPage.js b/src/components/ConfirmationPage.js
index 4549d6ca6072..bc154923e926 100644
--- a/src/components/ConfirmationPage.js
+++ b/src/components/ConfirmationPage.js
@@ -1,12 +1,12 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
+import styles from '@styles/styles';
+import Button from './Button';
+import FixedFooter from './FixedFooter';
import Lottie from './Lottie';
import * as LottieAnimations from './LottieAnimations';
import Text from './Text';
-import styles from '../styles/styles';
-import Button from './Button';
-import FixedFooter from './FixedFooter';
const propTypes = {
/** The asset to render */
diff --git a/src/components/ConfirmedRoute.js b/src/components/ConfirmedRoute.js
index 8544de62eeb9..656e419449b3 100644
--- a/src/components/ConfirmedRoute.js
+++ b/src/components/ConfirmedRoute.js
@@ -1,21 +1,20 @@
-import React, {useEffect} from 'react';
-import PropTypes from 'prop-types';
-
-import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import lodashIsNil from 'lodash/isNil';
+import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
+import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
-import * as MapboxToken from '../libs/actions/MapboxToken';
-import * as TransactionUtils from '../libs/TransactionUtils';
+import useNetwork from '@hooks/useNetwork';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import styles from '@styles/styles';
+import theme from '@styles/themes/default';
+import * as MapboxToken from '@userActions/MapboxToken';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import DistanceMapView from './DistanceMapView';
import * as Expensicons from './Icon/Expensicons';
-import theme from '../styles/themes/default';
-import styles from '../styles/styles';
-import transactionPropTypes from './transactionPropTypes';
import PendingMapView from './MapView/PendingMapView';
-import useNetwork from '../hooks/useNetwork';
-import DistanceMapView from './DistanceMapView';
+import transactionPropTypes from './transactionPropTypes';
const propTypes = {
/** Transaction that stores the distance request data */
diff --git a/src/components/ConnectBankAccountButton.js b/src/components/ConnectBankAccountButton.js
index f5e0afe1d52e..64d2421c7d37 100644
--- a/src/components/ConnectBankAccountButton.js
+++ b/src/components/ConnectBankAccountButton.js
@@ -1,16 +1,16 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
-import * as ReimbursementAccount from '../libs/actions/ReimbursementAccount';
-import * as Expensicons from './Icon/Expensicons';
-import styles from '../styles/styles';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as ReimbursementAccount from '@userActions/ReimbursementAccount';
import Button from './Button';
-import {withNetwork} from './OnyxProvider';
-import compose from '../libs/compose';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
+import * as Expensicons from './Icon/Expensicons';
import networkPropTypes from './networkPropTypes';
+import {withNetwork} from './OnyxProvider';
import Text from './Text';
-import Navigation from '../libs/Navigation/Navigation';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/components/ContextMenuItem.js b/src/components/ContextMenuItem.js
index 4c740caea78a..80d4855392a4 100644
--- a/src/components/ContextMenuItem.js
+++ b/src/components/ContextMenuItem.js
@@ -1,14 +1,14 @@
-import React, {forwardRef, useImperativeHandle} from 'react';
import PropTypes from 'prop-types';
-import MenuItem from './MenuItem';
-import Icon from './Icon';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import getButtonState from '../libs/getButtonState';
-import useThrottledButtonState from '../hooks/useThrottledButtonState';
+import React, {forwardRef, useImperativeHandle} from 'react';
+import useThrottledButtonState from '@hooks/useThrottledButtonState';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import getButtonState from '@libs/getButtonState';
+import getContextMenuItemStyles from '@styles/getContextMenuItemStyles';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import BaseMiniContextMenuItem from './BaseMiniContextMenuItem';
-import useWindowDimensions from '../hooks/useWindowDimensions';
-import getContextMenuItemStyles from '../styles/getContextMenuItemStyles';
+import Icon from './Icon';
+import MenuItem from './MenuItem';
const propTypes = {
/** Icon Component */
@@ -109,10 +109,14 @@ ContextMenuItem.propTypes = propTypes;
ContextMenuItem.defaultProps = defaultProps;
ContextMenuItem.displayName = 'ContextMenuItem';
-export default forwardRef((props, ref) => (
+const ContextMenuItemWithRef = forwardRef((props, ref) => (
));
+
+ContextMenuItemWithRef.displayName = 'ContextMenuItemWithRef';
+
+export default ContextMenuItemWithRef;
diff --git a/src/components/CopyTextToClipboard.js b/src/components/CopyTextToClipboard.js
index 6adc45cbdf52..ac396c6cedf4 100644
--- a/src/components/CopyTextToClipboard.js
+++ b/src/components/CopyTextToClipboard.js
@@ -1,8 +1,8 @@
-import React, {useCallback} from 'react';
import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
+import Clipboard from '@libs/Clipboard';
import * as Expensicons from './Icon/Expensicons';
import PressableWithDelayToggle from './Pressable/PressableWithDelayToggle';
-import Clipboard from '../libs/Clipboard';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
diff --git a/src/components/CountrySelector.js b/src/components/CountrySelector.js
index 2788f3cea8e3..93a90dcf6be9 100644
--- a/src/components/CountrySelector.js
+++ b/src/components/CountrySelector.js
@@ -1,12 +1,12 @@
-import React, {useEffect} from 'react';
import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
import {View} from 'react-native';
-import styles from '../styles/styles';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
-import useLocalize from '../hooks/useLocalize';
-import MenuItemWithTopDescription from './MenuItemWithTopDescription';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import ROUTES from '@src/ROUTES';
import FormHelpMessage from './FormHelpMessage';
+import MenuItemWithTopDescription from './MenuItemWithTopDescription';
const propTypes = {
/** Form error text. e.g when no country is selected */
@@ -68,10 +68,14 @@ CountrySelector.propTypes = propTypes;
CountrySelector.defaultProps = defaultProps;
CountrySelector.displayName = 'CountrySelector';
-export default React.forwardRef((props, ref) => (
+const CountrySelectorWithRef = React.forwardRef((props, ref) => (
));
+
+CountrySelectorWithRef.displayName = 'CountrySelectorWithRef';
+
+export default CountrySelectorWithRef;
diff --git a/src/components/CurrencySymbolButton.js b/src/components/CurrencySymbolButton.js
index ab4488c65f49..695cb2bc10c8 100644
--- a/src/components/CurrencySymbolButton.js
+++ b/src/components/CurrencySymbolButton.js
@@ -1,11 +1,11 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import Text from './Text';
-import styles from '../styles/styles';
import Tooltip from './Tooltip';
-import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
-import CONST from '../CONST';
-import useLocalize from '../hooks/useLocalize';
const propTypes = {
/** Currency symbol of selected currency */
@@ -18,10 +18,10 @@ const propTypes = {
function CurrencySymbolButton({onCurrencyButtonPress, currencySymbol}) {
const {translate} = useLocalize();
return (
-
+
{currencySymbol}
diff --git a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js
index cc305a628820..f2d7a8b71897 100644
--- a/src/components/CurrentUserPersonalDetailsSkeletonView/index.js
+++ b/src/components/CurrentUserPersonalDetailsSkeletonView/index.js
@@ -1,14 +1,14 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React from 'react';
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';
-import CONST from '../../CONST';
-import themeColors from '../../styles/themes/default';
-import variables from '../../styles/variables';
-import styles from '../../styles/styles';
+import {Circle, Rect} from 'react-native-svg';
+import _ from 'underscore';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether to animate the skeleton view */
diff --git a/src/components/CurrentWalletBalance.js b/src/components/CurrentWalletBalance.js
index 642e6937f1bf..c73c0815a003 100644
--- a/src/components/CurrentWalletBalance.js
+++ b/src/components/CurrentWalletBalance.js
@@ -1,12 +1,12 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import styles from '../styles/styles';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import compose from '../libs/compose';
-import ONYXKEYS from '../ONYXKEYS';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import styles from '@styles/styles';
+import ONYXKEYS from '@src/ONYXKEYS';
import Text from './Text';
-import * as CurrencyUtils from '../libs/CurrencyUtils';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** The user's wallet account */
diff --git a/src/components/CustomDevMenu/index.native.js b/src/components/CustomDevMenu/index.native.js
index 52ca0e43782c..c8d0e1e099d4 100644
--- a/src/components/CustomDevMenu/index.native.js
+++ b/src/components/CustomDevMenu/index.native.js
@@ -1,6 +1,6 @@
import {useEffect} from 'react';
import DevMenu from 'react-native-dev-menu';
-import toggleTestToolsModal from '../../libs/actions/TestTool';
+import toggleTestToolsModal from '@userActions/TestTool';
function CustomDevMenu() {
useEffect(() => {
diff --git a/src/components/CustomStatusBar/index.js b/src/components/CustomStatusBar/index.js
index 4848e6e35f59..2ffd763bf088 100644
--- a/src/components/CustomStatusBar/index.js
+++ b/src/components/CustomStatusBar/index.js
@@ -1,7 +1,7 @@
import React, {useEffect} from 'react';
-import StatusBar from '../../libs/StatusBar';
-import Navigation, {navigationRef} from '../../libs/Navigation/Navigation';
-import themeColors from '../../styles/themes/default';
+import Navigation, {navigationRef} from '@libs/Navigation/Navigation';
+import StatusBar from '@libs/StatusBar';
+import themeColors from '@styles/themes/default';
function CustomStatusBar() {
useEffect(() => {
diff --git a/src/components/DatePicker/datepickerPropTypes.js b/src/components/DatePicker/datepickerPropTypes.js
index 8bd5d890c42c..c895d919cd33 100644
--- a/src/components/DatePicker/datepickerPropTypes.js
+++ b/src/components/DatePicker/datepickerPropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import {propTypes as fieldPropTypes, defaultProps as defaultFieldPropTypes} from '../TextInput/baseTextInputPropTypes';
-import CONST from '../../CONST';
+import {defaultProps as defaultFieldPropTypes, propTypes as fieldPropTypes} from '@components/TextInput/baseTextInputPropTypes';
+import CONST from '@src/CONST';
const propTypes = {
...fieldPropTypes,
diff --git a/src/components/DatePicker/index.android.js b/src/components/DatePicker/index.android.js
index 4c034038305d..002cf5587e44 100644
--- a/src/components/DatePicker/index.android.js
+++ b/src/components/DatePicker/index.android.js
@@ -1,11 +1,11 @@
-import React, {forwardRef, useCallback, useImperativeHandle, useRef, useState} from 'react';
-import {Keyboard} from 'react-native';
import RNDatePicker from '@react-native-community/datetimepicker';
import moment from 'moment';
-import TextInput from '../TextInput';
-import CONST from '../../CONST';
-import {propTypes, defaultProps} from './datepickerPropTypes';
-import styles from '../../styles/styles';
+import React, {forwardRef, useCallback, useImperativeHandle, useRef, useState} from 'react';
+import {Keyboard} from 'react-native';
+import TextInput from '@components/TextInput';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes} from './datepickerPropTypes';
function DatePicker({value, defaultValue, label, placeholder, errorText, containerStyles, disabled, onBlur, onInputChange, maxDate, minDate}, outerRef) {
const ref = useRef();
diff --git a/src/components/DatePicker/index.ios.js b/src/components/DatePicker/index.ios.js
index ef40aecb6f8c..705792b0fad8 100644
--- a/src/components/DatePicker/index.ios.js
+++ b/src/components/DatePicker/index.ios.js
@@ -1,16 +1,16 @@
-import React, {useState, useRef, useCallback, useEffect} from 'react';
-import {Button, View, Keyboard} from 'react-native';
import RNDatePicker from '@react-native-community/datetimepicker';
-import moment from 'moment';
import isFunction from 'lodash/isFunction';
-import TextInput from '../TextInput';
-import Popover from '../Popover';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import {propTypes, defaultProps} from './datepickerPropTypes';
-import useKeyboardState from '../../hooks/useKeyboardState';
-import useLocalize from '../../hooks/useLocalize';
+import moment from 'moment';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
+import {Button, Keyboard, View} from 'react-native';
+import Popover from '@components/Popover';
+import TextInput from '@components/TextInput';
+import useKeyboardState from '@hooks/useKeyboardState';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes} from './datepickerPropTypes';
function DatePicker({value, defaultValue, innerRef, onInputChange, preferredLocale, minDate, maxDate, label, disabled, onBlur, placeholder, containerStyles, errorText}) {
const [isPickerVisible, setIsPickerVisible] = useState(false);
@@ -138,10 +138,14 @@ DatePicker.displayName = 'DatePicker';
* locale. Otherwise the spinner would be present in the system locale and it would be weird if it happens
* that the modal buttons are in one locale (app) while the (spinner) month names are another (system)
*/
-export default React.forwardRef((props, ref) => (
+const DatePickerWithRef = React.forwardRef((props, ref) => (
));
+
+DatePickerWithRef.displayName = 'DatePickerWithRef';
+
+export default DatePickerWithRef;
diff --git a/src/components/DatePicker/index.js b/src/components/DatePicker/index.js
index d14886fd1c59..a5b282b22c73 100644
--- a/src/components/DatePicker/index.js
+++ b/src/components/DatePicker/index.js
@@ -1,10 +1,10 @@
-import React, {useEffect, useRef} from 'react';
import moment from 'moment';
+import React, {useEffect, useRef} from 'react';
import _ from 'underscore';
-import TextInput from '../TextInput';
-import CONST from '../../CONST';
-import * as Browser from '../../libs/Browser';
-import {propTypes, defaultProps} from './datepickerPropTypes';
+import TextInput from '@components/TextInput';
+import * as Browser from '@libs/Browser';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes} from './datepickerPropTypes';
import './styles.css';
function DatePicker({maxDate, minDate, onInputChange, innerRef, label, value, placeholder, errorText, containerStyles, disabled, onBlur}) {
@@ -77,10 +77,14 @@ DatePicker.displayName = 'DatePicker';
DatePicker.propTypes = propTypes;
DatePicker.defaultProps = defaultProps;
-export default React.forwardRef((props, ref) => (
+const DatePickerWithRef = React.forwardRef((props, ref) => (
));
+
+DatePickerWithRef.displayName = 'DatePickerWithRef';
+
+export default DatePickerWithRef;
diff --git a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js
index 61614c7e49e6..671744a3d59c 100644
--- a/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js
+++ b/src/components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator.js
@@ -1,19 +1,19 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import TextLink from '../TextLink';
-import Text from '../Text';
-import Icon from '../Icon';
-import * as Illustrations from '../Icon/Illustrations';
-import * as Expensicons from '../Icon/Expensicons';
-import themeColors from '../../styles/themes/default';
-import styles from '../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
openLinkInBrowser: PropTypes.func.isRequired,
diff --git a/src/components/DeeplinkWrapper/index.website.js b/src/components/DeeplinkWrapper/index.website.js
index 0cd7bfd93241..166818e4ae27 100644
--- a/src/components/DeeplinkWrapper/index.website.js
+++ b/src/components/DeeplinkWrapper/index.website.js
@@ -1,15 +1,15 @@
-import PropTypes from 'prop-types';
-import {useRef, useState, useEffect} from 'react';
import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
+import {useEffect, useRef, useState} from 'react';
import _ from 'underscore';
-import * as Browser from '../../libs/Browser';
-import ROUTES from '../../ROUTES';
-import * as App from '../../libs/actions/App';
-import CONST from '../../CONST';
-import CONFIG from '../../CONFIG';
-import shouldPreventDeeplinkPrompt from '../../libs/Navigation/shouldPreventDeeplinkPrompt';
-import navigationRef from '../../libs/Navigation/navigationRef';
-import Navigation from '../../libs/Navigation/Navigation';
+import * as Browser from '@libs/Browser';
+import Navigation from '@libs/Navigation/Navigation';
+import navigationRef from '@libs/Navigation/navigationRef';
+import shouldPreventDeeplinkPrompt from '@libs/Navigation/shouldPreventDeeplinkPrompt';
+import * as App from '@userActions/App';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Children to render. */
diff --git a/src/components/DisplayNames/DisplayNamesTooltipItem.js b/src/components/DisplayNames/DisplayNamesTooltipItem.js
index 16f0f3a6420d..bc4d35777185 100644
--- a/src/components/DisplayNames/DisplayNamesTooltipItem.js
+++ b/src/components/DisplayNames/DisplayNamesTooltipItem.js
@@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import UserDetailsTooltip from '../UserDetailsTooltip';
+import Text from '@components/Text';
+import UserDetailsTooltip from '@components/UserDetailsTooltip';
+import styles from '@styles/styles';
const propTypes = {
index: PropTypes.number,
diff --git a/src/components/DisplayNames/DisplayNamesWithTooltip.js b/src/components/DisplayNames/DisplayNamesWithTooltip.js
index 0e8c435f4457..254ad3ff824f 100644
--- a/src/components/DisplayNames/DisplayNamesWithTooltip.js
+++ b/src/components/DisplayNames/DisplayNamesWithTooltip.js
@@ -1,12 +1,12 @@
+import lodashGet from 'lodash/get';
import React, {Fragment, useCallback, useRef} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import Tooltip from '../Tooltip';
-import DisplayNamesTooltipItem from './DisplayNamesTooltipItem';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import styles from '@styles/styles';
import {defaultProps, propTypes} from './displayNamesPropTypes';
+import DisplayNamesTooltipItem from './DisplayNamesTooltipItem';
function DisplayNamesWithToolTip(props) {
const containerRef = useRef(null);
diff --git a/src/components/DisplayNames/DisplayNamesWithoutTooltip.js b/src/components/DisplayNames/DisplayNamesWithoutTooltip.js
index 66604d09673c..bdc26d4c3f8d 100644
--- a/src/components/DisplayNames/DisplayNamesWithoutTooltip.js
+++ b/src/components/DisplayNames/DisplayNamesWithoutTooltip.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
-import styles from '../../styles/styles';
-import Text from '../Text';
+import Text from '@components/Text';
+import styles from '@styles/styles';
const propTypes = {
/** The full title of the DisplayNames component (not split up) */
diff --git a/src/components/DisplayNames/displayNamesPropTypes.js b/src/components/DisplayNames/displayNamesPropTypes.js
index 5ad332f7a117..0f5a2a304b29 100644
--- a/src/components/DisplayNames/displayNamesPropTypes.js
+++ b/src/components/DisplayNames/displayNamesPropTypes.js
@@ -34,7 +34,7 @@ const propTypes = {
const defaultProps = {
numberOfLines: 1,
tooltipEnabled: false,
- titleStyles: [],
+ textStyles: [],
};
export {propTypes, defaultProps};
diff --git a/src/components/DisplayNames/index.js b/src/components/DisplayNames/index.js
index 197940d80ca6..52ec6fb89de2 100644
--- a/src/components/DisplayNames/index.js
+++ b/src/components/DisplayNames/index.js
@@ -1,7 +1,7 @@
import React from 'react';
-import DisplayNamesWithToolTip from './DisplayNamesWithTooltip';
-import DisplayNamesWithoutTooltip from './DisplayNamesWithoutTooltip';
import {defaultProps, propTypes} from './displayNamesPropTypes';
+import DisplayNamesWithoutTooltip from './DisplayNamesWithoutTooltip';
+import DisplayNamesWithToolTip from './DisplayNamesWithTooltip';
function DisplayNames(props) {
if (!props.tooltipEnabled) {
diff --git a/src/components/DisplayNames/index.native.js b/src/components/DisplayNames/index.native.js
index f1b1d7d0b7b5..e0f9635c0132 100644
--- a/src/components/DisplayNames/index.native.js
+++ b/src/components/DisplayNames/index.native.js
@@ -1,6 +1,6 @@
import React from 'react';
-import {propTypes, defaultProps} from './displayNamesPropTypes';
-import Text from '../Text';
+import Text from '@components/Text';
+import {defaultProps, propTypes} from './displayNamesPropTypes';
// As we don't have to show tooltips of the Native platform so we simply render the full display names list.
function DisplayNames(props) {
diff --git a/src/components/DistanceEReceipt.js b/src/components/DistanceEReceipt.js
index f866de0b885e..9a63ff3a9df5 100644
--- a/src/components/DistanceEReceipt.js
+++ b/src/components/DistanceEReceipt.js
@@ -1,23 +1,23 @@
-import React, {useMemo} from 'react';
-import {View, ScrollView} from 'react-native';
import lodashGet from 'lodash/get';
+import React, {useMemo} from 'react';
+import {ScrollView, View} from 'react-native';
import _ from 'underscore';
-import Text from './Text';
-import styles from '../styles/styles';
-import transactionPropTypes from './transactionPropTypes';
-import * as ReceiptUtils from '../libs/ReceiptUtils';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as CurrencyUtils from '../libs/CurrencyUtils';
-import * as TransactionUtils from '../libs/TransactionUtils';
-import tryResolveUrlFromApiRoot from '../libs/tryResolveUrlFromApiRoot';
-import ThumbnailImage from './ThumbnailImage';
-import useLocalize from '../hooks/useLocalize';
+import EReceiptBackground from '@assets/images/eReceipt_background.svg';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as ReceiptUtils from '@libs/ReceiptUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
import Icon from './Icon';
-import themeColors from '../styles/themes/default';
import * as Expensicons from './Icon/Expensicons';
-import EReceiptBackground from '../../assets/images/eReceipt_background.svg';
-import useNetwork from '../hooks/useNetwork';
import PendingMapView from './MapView/PendingMapView';
+import Text from './Text';
+import ThumbnailImage from './ThumbnailImage';
+import transactionPropTypes from './transactionPropTypes';
const propTypes = {
/** The transaction for the distance request */
@@ -91,7 +91,8 @@ function DistanceEReceipt({transaction}) {
key={key}
>
{translate(descriptionKey)}
- {waypoint.address || ''}
+ {waypoint.name && {waypoint.name} }
+ {waypoint.address && {waypoint.address} }
);
})}
diff --git a/src/components/DistanceMapView/index.android.js b/src/components/DistanceMapView/index.android.js
index ea72fb4de299..358b2f483a2b 100644
--- a/src/components/DistanceMapView/index.android.js
+++ b/src/components/DistanceMapView/index.android.js
@@ -1,13 +1,13 @@
import React, {useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import BlockingView from '../BlockingViews/BlockingView';
-import MapView from '../MapView';
-import styles from '../../styles/styles';
-import useNetwork from '../../hooks/useNetwork';
-import useLocalize from '../../hooks/useLocalize';
-import * as Expensicons from '../Icon/Expensicons';
-import * as StyleUtils from '../../styles/StyleUtils';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MapView from '@components/MapView';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import * as distanceMapViewPropTypes from './distanceMapViewPropTypes';
function DistanceMapView(props) {
diff --git a/src/components/DistanceMapView/index.js b/src/components/DistanceMapView/index.js
index 24bdf99382d1..49f47122dd4a 100644
--- a/src/components/DistanceMapView/index.js
+++ b/src/components/DistanceMapView/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import _ from 'underscore';
-import MapView from '../MapView';
+import MapView from '@components/MapView';
import * as distanceMapViewPropTypes from './distanceMapViewPropTypes';
function DistanceMapView(props) {
diff --git a/src/components/DistanceRequest/DistanceRequestFooter.js b/src/components/DistanceRequest/DistanceRequestFooter.js
index d8214774d2c1..e476b2fa6d34 100644
--- a/src/components/DistanceRequest/DistanceRequestFooter.js
+++ b/src/components/DistanceRequest/DistanceRequestFooter.js
@@ -1,22 +1,22 @@
-import React, {useMemo} from 'react';
-import {View} from 'react-native';
-import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import lodashIsNil from 'lodash/isNil';
import PropTypes from 'prop-types';
+import React, {useMemo} from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
-import styles from '../../styles/styles';
-import useNetwork from '../../hooks/useNetwork';
-import useLocalize from '../../hooks/useLocalize';
-import theme from '../../styles/themes/default';
-import * as TransactionUtils from '../../libs/TransactionUtils';
-import Button from '../Button';
-import DistanceMapView from '../DistanceMapView';
-import * as Expensicons from '../Icon/Expensicons';
-import PendingMapView from '../MapView/PendingMapView';
-import transactionPropTypes from '../transactionPropTypes';
+import Button from '@components/Button';
+import DistanceMapView from '@components/DistanceMapView';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PendingMapView from '@components/MapView/PendingMapView';
+import transactionPropTypes from '@components/transactionPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import styles from '@styles/styles';
+import theme from '@styles/themes/default';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const MAX_WAYPOINTS = 25;
@@ -27,6 +27,7 @@ const propTypes = {
lat: PropTypes.number,
lng: PropTypes.number,
address: PropTypes.string,
+ name: PropTypes.string,
}),
),
diff --git a/src/components/DistanceRequest/DistanceRequestRenderItem.js b/src/components/DistanceRequest/DistanceRequestRenderItem.js
index 4e4eeee881c5..0ee45febb21a 100644
--- a/src/components/DistanceRequest/DistanceRequestRenderItem.js
+++ b/src/components/DistanceRequest/DistanceRequestRenderItem.js
@@ -1,11 +1,11 @@
-import React from 'react';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
import PropTypes from 'prop-types';
-import * as Expensicons from '../Icon/Expensicons';
-import MenuItemWithTopDescription from '../MenuItemWithTopDescription';
-import theme from '../../styles/themes/default';
-import useLocalize from '../../hooks/useLocalize';
+import React from 'react';
+import _ from 'underscore';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import useLocalize from '@hooks/useLocalize';
+import theme from '@styles/themes/default';
const propTypes = {
/** The waypoints for the distance request */
@@ -14,6 +14,7 @@ const propTypes = {
lat: PropTypes.number,
lng: PropTypes.number,
address: PropTypes.string,
+ name: PropTypes.string,
}),
),
@@ -65,10 +66,13 @@ function DistanceRequestRenderItem({waypoints, item, onSecondaryInteraction, get
waypointIcon = Expensicons.DotIndicator;
}
+ const waypoint = lodashGet(waypoints, [`waypoint${index}`], {});
+ const title = waypoint.name || waypoint.address;
+
return (
({renderClone, shouldUsePortal, ...viewProps}: DraggableListProps, ref: React.ForwardedRef>) {
return (
diff --git a/src/components/DraggableList/index.tsx b/src/components/DraggableList/index.tsx
index ea9ac548e850..287b549d6d0a 100644
--- a/src/components/DraggableList/index.tsx
+++ b/src/components/DraggableList/index.tsx
@@ -1,9 +1,9 @@
import React, {useCallback} from 'react';
-import {DragDropContext, Droppable, Draggable, type OnDragEndResponder} from 'react-beautiful-dnd';
+import {DragDropContext, Draggable, Droppable, type OnDragEndResponder} from 'react-beautiful-dnd';
import {ScrollView} from 'react-native';
-import useDraggableInPortal from './useDraggableInPortal';
+import styles from '@styles/styles';
import type {DraggableListProps} from './types';
-import styles from '../../styles/styles';
+import useDraggableInPortal from './useDraggableInPortal';
type ReorderParams = {
list: T[];
diff --git a/src/components/DraggableList/useDraggableInPortal.ts b/src/components/DraggableList/useDraggableInPortal.ts
index 6b7f958d6a3e..3b4610ce1e5e 100644
--- a/src/components/DraggableList/useDraggableInPortal.ts
+++ b/src/components/DraggableList/useDraggableInPortal.ts
@@ -1,5 +1,5 @@
-import type {DraggableChildrenFn} from 'react-beautiful-dnd';
import {useEffect, useRef} from 'react';
+import type {DraggableChildrenFn} from 'react-beautiful-dnd';
import {createPortal} from 'react-dom';
type DraggableInPortal = {
diff --git a/src/components/EReceipt.js b/src/components/EReceipt.js
index 84daabb96c9b..7c186216a1fa 100644
--- a/src/components/EReceipt.js
+++ b/src/components/EReceipt.js
@@ -1,21 +1,21 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import ONYXKEYS from '../ONYXKEYS';
-import * as StyleUtils from '../styles/StyleUtils';
-import transactionPropTypes from './transactionPropTypes';
-import styles from '../styles/styles';
-import * as Expensicons from './Icon/Expensicons';
+import useLocalize from '@hooks/useLocalize';
+import * as CardUtils from '@libs/CardUtils';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import EReceiptThumbnail from './EReceiptThumbnail';
import Icon from './Icon';
+import * as Expensicons from './Icon/Expensicons';
import Text from './Text';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as CurrencyUtils from '../libs/CurrencyUtils';
-import * as CardUtils from '../libs/CardUtils';
-import variables from '../styles/variables';
-import useLocalize from '../hooks/useLocalize';
-import EReceiptThumbnail from './EReceiptThumbnail';
-import CONST from '../CONST';
+import transactionPropTypes from './transactionPropTypes';
const propTypes = {
/* TransactionID of the transaction this EReceipt corresponds to */
diff --git a/src/components/EReceiptThumbnail.js b/src/components/EReceiptThumbnail.js
index f1bb5b025e2f..fc69601983f8 100644
--- a/src/components/EReceiptThumbnail.js
+++ b/src/components/EReceiptThumbnail.js
@@ -1,19 +1,19 @@
+import PropTypes from 'prop-types';
import React, {useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import ONYXKEYS from '../ONYXKEYS';
-import * as StyleUtils from '../styles/StyleUtils';
-import transactionPropTypes from './transactionPropTypes';
-import styles from '../styles/styles';
-import * as Expensicons from './Icon/Expensicons';
-import * as MCCIcons from './Icon/MCCIcons';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import Icon from './Icon';
-import * as ReportUtils from '../libs/ReportUtils';
-import variables from '../styles/variables';
import * as eReceiptBGs from './Icon/EReceiptBGs';
+import * as Expensicons from './Icon/Expensicons';
+import * as MCCIcons from './Icon/MCCIcons';
import Image from './Image';
-import CONST from '../CONST';
+import transactionPropTypes from './transactionPropTypes';
const propTypes = {
/* TransactionID of the transaction this EReceipt corresponds to */
diff --git a/src/components/EmojiPicker/CategoryShortcutBar.js b/src/components/EmojiPicker/CategoryShortcutBar.js
index 00fee688f986..bab1e344da40 100644
--- a/src/components/EmojiPicker/CategoryShortcutBar.js
+++ b/src/components/EmojiPicker/CategoryShortcutBar.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../../styles/styles';
+import styles from '@styles/styles';
import CategoryShortcutButton from './CategoryShortcutButton';
const propTypes = {
diff --git a/src/components/EmojiPicker/CategoryShortcutButton.js b/src/components/EmojiPicker/CategoryShortcutButton.js
index a7658ae0542d..132da7c540c2 100644
--- a/src/components/EmojiPicker/CategoryShortcutButton.js
+++ b/src/components/EmojiPicker/CategoryShortcutButton.js
@@ -1,15 +1,15 @@
-import React, {useState} from 'react';
import PropTypes from 'prop-types';
-import Icon from '../Icon';
-import Tooltip from '../Tooltip';
-import useLocalize from '../../hooks/useLocalize';
-import variables from '../../styles/variables';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
-import getButtonState from '../../libs/getButtonState';
-import themeColors from '../../styles/themes/default';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import CONST from '../../CONST';
+import React, {useState} from 'react';
+import Icon from '@components/Icon';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Tooltip from '@components/Tooltip';
+import useLocalize from '@hooks/useLocalize';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
const propTypes = {
/** The emoji code of the category header */
diff --git a/src/components/EmojiPicker/EmojiPicker.js b/src/components/EmojiPicker/EmojiPicker.js
index 5c2f65e24b01..d0ba8f80f94b 100644
--- a/src/components/EmojiPicker/EmojiPicker.js
+++ b/src/components/EmojiPicker/EmojiPicker.js
@@ -1,15 +1,15 @@
-import React, {useState, useEffect, useRef, forwardRef, useImperativeHandle} from 'react';
+import PropTypes from 'prop-types';
+import React, {forwardRef, useEffect, useImperativeHandle, useRef, useState} from 'react';
import {Dimensions} from 'react-native';
import _ from 'underscore';
-import PropTypes from 'prop-types';
+import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent';
+import withViewportOffsetTop from '@components/withViewportOffsetTop';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import calculateAnchorPosition from '@libs/calculateAnchorPosition';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import EmojiPickerMenu from './EmojiPickerMenu';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import PopoverWithMeasuredContent from '../PopoverWithMeasuredContent';
-import withViewportOffsetTop from '../withViewportOffsetTop';
-import * as StyleUtils from '../../styles/StyleUtils';
-import calculateAnchorPosition from '../../libs/calculateAnchorPosition';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
const DEFAULT_ANCHOR_ORIGIN = {
horizontal: CONST.MODAL.ANCHOR_ORIGIN_HORIZONTAL.RIGHT,
diff --git a/src/components/EmojiPicker/EmojiPickerButton.js b/src/components/EmojiPicker/EmojiPickerButton.js
index 0d1426cbf987..0989e4df88c6 100644
--- a/src/components/EmojiPicker/EmojiPickerButton.js
+++ b/src/components/EmojiPicker/EmojiPickerButton.js
@@ -1,14 +1,14 @@
-import React, {useEffect, useRef} from 'react';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
-import getButtonState from '../../libs/getButtonState';
-import * as Expensicons from '../Icon/Expensicons';
-import Tooltip from '../Tooltip/PopoverAnchorTooltip';
-import Icon from '../Icon';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
+import React, {useEffect, useRef} from 'react';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
const propTypes = {
/** Flag to disable the emoji picker button */
diff --git a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
index 0dc967d257d2..8a5a66444fda 100644
--- a/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
+++ b/src/components/EmojiPicker/EmojiPickerButtonDropdown.js
@@ -1,17 +1,17 @@
-import React, {useRef, useEffect} from 'react';
import PropTypes from 'prop-types';
+import React, {useEffect, useRef} from 'react';
import {View} from 'react-native';
-import styles from '../../styles/styles';
-import CONST from '../../CONST';
-import * as StyleUtils from '../../styles/StyleUtils';
-import getButtonState from '../../libs/getButtonState';
-import * as Expensicons from '../Icon/Expensicons';
-import Tooltip from '../Tooltip';
-import Text from '../Text';
-import Icon from '../Icon';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
+import CONST from '@src/CONST';
const propTypes = {
/** Flag to disable the emoji picker button */
@@ -76,12 +76,15 @@ function EmojiPickerButtonDropdown(props) {
EmojiPickerButtonDropdown.propTypes = propTypes;
EmojiPickerButtonDropdown.defaultProps = defaultProps;
EmojiPickerButtonDropdown.displayName = 'EmojiPickerButtonDropdown';
-export default withLocalize(
- React.forwardRef((props, ref) => (
-
- )),
-);
+
+const EmojiPickerButtonDropdownWithRef = React.forwardRef((props, ref) => (
+
+));
+
+EmojiPickerButtonDropdownWithRef.displayName = 'EmojiPickerButtonDropdownWithRef';
+
+export default withLocalize(EmojiPickerButtonDropdownWithRef);
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js
index aea3b0f5b984..7dc53e958849 100755
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js
@@ -1,28 +1,28 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useRef, useState} from 'react';
-import {View, FlatList} from 'react-native';
+import {FlatList, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import CONST from '../../../CONST';
-import ONYXKEYS from '../../../ONYXKEYS';
-import styles from '../../../styles/styles';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import emojiAssets from '../../../../assets/emojis';
-import EmojiPickerMenuItem from '../EmojiPickerMenuItem';
-import Text from '../../Text';
-import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
-import compose from '../../../libs/compose';
-import getOperatingSystem from '../../../libs/getOperatingSystem';
-import * as User from '../../../libs/actions/User';
-import EmojiSkinToneList from '../EmojiSkinToneList';
-import * as EmojiUtils from '../../../libs/EmojiUtils';
-import * as Browser from '../../../libs/Browser';
-import CategoryShortcutBar from '../CategoryShortcutBar';
-import TextInput from '../../TextInput';
-import isEnterWhileComposition from '../../../libs/KeyboardShortcut/isEnterWhileComposition';
-import canFocusInputOnScreenFocus from '../../../libs/canFocusInputOnScreenFocus';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
+import emojiAssets from '@assets/emojis';
+import CategoryShortcutBar from '@components/EmojiPicker/CategoryShortcutBar';
+import EmojiPickerMenuItem from '@components/EmojiPicker/EmojiPickerMenuItem';
+import EmojiSkinToneList from '@components/EmojiPicker/EmojiSkinToneList';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
+import compose from '@libs/compose';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import getOperatingSystem from '@libs/getOperatingSystem';
+import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Function to add the selected emoji to the main compose text input */
@@ -107,6 +107,7 @@ function EmojiPickerMenu(props) {
const [selection, setSelection] = useState({start: 0, end: 0});
const [isFocused, setIsFocused] = useState(false);
const [isUsingKeyboardMovement, setIsUsingKeyboardMovement] = useState(false);
+ const [highlightFirstEmoji, setHighlightFirstEmoji] = useState(false);
useEffect(() => {
const emojisAndHeaderRowIndices = getEmojisAndHeaderRowIndices();
@@ -174,6 +175,7 @@ function EmojiPickerMenu(props) {
setHeaderIndices(headerRowIndices.current);
setHighlightedIndex(-1);
updateFirstNonHeaderIndex(emojis.current);
+ setHighlightFirstEmoji(false);
return;
}
const newFilteredEmojiList = EmojiUtils.suggestEmojis(`:${normalizedSearchTerm}`, preferredLocale, emojis.current.length);
@@ -183,6 +185,7 @@ function EmojiPickerMenu(props) {
setHeaderIndices([]);
setHighlightedIndex(0);
updateFirstNonHeaderIndex(newFilteredEmojiList);
+ setHighlightFirstEmoji(true);
}, throttleTime);
/**
@@ -209,6 +212,7 @@ function EmojiPickerMenu(props) {
searchInputRef.current.blur();
setArePointerEventsDisabled(true);
setIsUsingKeyboardMovement(true);
+ setHighlightFirstEmoji(false);
// We only want to hightlight the Emoji if none was highlighted already
// If we already have a highlighted Emoji, lets just skip the first navigation
@@ -434,11 +438,13 @@ function EmojiPickerMenu(props) {
const emojiCode = types && types[preferredSkinTone] ? types[preferredSkinTone] : code;
const isEmojiFocused = index === highlightedIndex && isUsingKeyboardMovement;
+ const shouldEmojiBeHighlighted = index === highlightedIndex && highlightFirstEmoji;
return (
onEmojiSelected(emoji, item)}
onHoverIn={() => {
+ setHighlightFirstEmoji(false);
if (!isUsingKeyboardMovement) {
return;
}
@@ -452,10 +458,11 @@ function EmojiPickerMenu(props) {
setHighlightedIndex((prevState) => (prevState === index ? -1 : prevState))
}
isFocused={isEmojiFocused}
+ isHighlighted={shouldEmojiBeHighlighted}
/>
);
},
- [isUsingKeyboardMovement, highlightedIndex, onEmojiSelected, preferredSkinTone, translate],
+ [isUsingKeyboardMovement, highlightedIndex, onEmojiSelected, preferredSkinTone, translate, highlightFirstEmoji],
);
const isFiltered = emojis.current.length !== filteredEmojis.length;
@@ -526,6 +533,16 @@ function EmojiPickerMenu(props) {
EmojiPickerMenu.propTypes = propTypes;
EmojiPickerMenu.defaultProps = defaultProps;
+const EmojiPickerMenuWithRef = React.forwardRef((props, ref) => (
+
+));
+
+EmojiPickerMenuWithRef.displayName = 'EmojiPickerMenuWithRef';
+
export default compose(
withLocalize,
withOnyx({
@@ -536,12 +553,4 @@ export default compose(
key: ONYXKEYS.FREQUENTLY_USED_EMOJIS,
},
}),
-)(
- React.forwardRef((props, ref) => (
-
- )),
-);
+)(EmojiPickerMenuWithRef);
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
index fe8c3e275ad2..140dd8f2625c 100644
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
@@ -1,25 +1,25 @@
-import React, {useState, useMemo, useEffect} from 'react';
+import PropTypes from 'prop-types';
+import React, {useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
import Animated, {runOnUI, scrollTo, useAnimatedRef} from 'react-native-reanimated';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
-import compose from '../../../libs/compose';
-import CONST from '../../../CONST';
-import ONYXKEYS from '../../../ONYXKEYS';
-import styles from '../../../styles/styles';
-import emojis from '../../../../assets/emojis';
-import EmojiPickerMenuItem from '../EmojiPickerMenuItem';
-import Text from '../../Text';
-import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
-import EmojiSkinToneList from '../EmojiSkinToneList';
-import * as EmojiUtils from '../../../libs/EmojiUtils';
-import * as User from '../../../libs/actions/User';
-import TextInput from '../../TextInput';
-import CategoryShortcutBar from '../CategoryShortcutBar';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import useSingleExecution from '../../../hooks/useSingleExecution';
+import _ from 'underscore';
+import emojis from '@assets/emojis';
+import CategoryShortcutBar from '@components/EmojiPicker/CategoryShortcutBar';
+import EmojiPickerMenuItem from '@components/EmojiPicker/EmojiPickerMenuItem';
+import EmojiSkinToneList from '@components/EmojiPicker/EmojiSkinToneList';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useSingleExecution from '@hooks/useSingleExecution';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import compose from '@libs/compose';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Function to add the selected emoji to the main compose text input */
@@ -201,6 +201,16 @@ EmojiPickerMenu.displayName = 'EmojiPickerMenu';
EmojiPickerMenu.propTypes = propTypes;
EmojiPickerMenu.defaultProps = defaultProps;
+const EmojiPickerMenuWithRef = React.forwardRef((props, ref) => (
+
+));
+
+EmojiPickerMenuWithRef.displayName = 'EmojiPickerMenuWithRef';
+
export default compose(
withLocalize,
withOnyx({
@@ -211,12 +221,4 @@ export default compose(
key: ONYXKEYS.FREQUENTLY_USED_EMOJIS,
},
}),
-)(
- React.forwardRef((props, ref) => (
-
- )),
-);
+)(EmojiPickerMenuWithRef);
diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem/index.js b/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
index c5ca5463aec4..90f7f966172f 100644
--- a/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenuItem/index.js
@@ -1,12 +1,12 @@
-import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import getButtonState from '../../../libs/getButtonState';
-import Text from '../../Text';
-import PressableWithoutFeedback from '../../Pressable/PressableWithoutFeedback';
-import CONST from '../../../CONST';
-import * as Browser from '../../../libs/Browser';
+import React, {PureComponent} from 'react';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import * as Browser from '@libs/Browser';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
const propTypes = {
/** The unicode that is used to display the emoji */
@@ -29,6 +29,9 @@ const propTypes = {
/** Whether this menu item is currently focused or not */
isFocused: PropTypes.bool,
+
+ /** Whether the menu item should be highlighted or not */
+ isHighlighted: PropTypes.bool,
};
class EmojiPickerMenuItem extends PureComponent {
@@ -56,6 +59,7 @@ class EmojiPickerMenuItem extends PureComponent {
if (!this.props.isFocused) {
return;
}
+
this.focusAndScroll();
}
@@ -91,7 +95,7 @@ class EmojiPickerMenuItem extends PureComponent {
ref={(ref) => (this.ref = ref)}
style={({pressed}) => [
this.props.isFocused ? styles.emojiItemKeyboardHighlighted : {},
- this.state.isHovered ? styles.emojiItemHighlighted : {},
+ this.state.isHovered || this.props.isHighlighted ? styles.emojiItemHighlighted : {},
Browser.isMobile() && StyleUtils.getButtonBackgroundColorStyle(getButtonState(false, pressed)),
styles.emojiItem,
]}
@@ -107,6 +111,7 @@ class EmojiPickerMenuItem extends PureComponent {
EmojiPickerMenuItem.propTypes = propTypes;
EmojiPickerMenuItem.defaultProps = {
isFocused: false,
+ isHighlighted: false,
onHoverIn: () => {},
onHoverOut: () => {},
onFocus: () => {},
@@ -115,4 +120,7 @@ EmojiPickerMenuItem.defaultProps = {
// Significantly speeds up re-renders of the EmojiPickerMenu's FlatList
// by only re-rendering at most two EmojiPickerMenuItems that are highlighted/un-highlighted per user action.
-export default React.memo(EmojiPickerMenuItem, (prevProps, nextProps) => prevProps.isFocused === nextProps.isFocused && prevProps.emoji === nextProps.emoji);
+export default React.memo(
+ EmojiPickerMenuItem,
+ (prevProps, nextProps) => prevProps.isFocused === nextProps.isFocused && prevProps.isHighlighted === nextProps.isHighlighted && prevProps.emoji === nextProps.emoji,
+);
diff --git a/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js b/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js
index 54416a4a2518..099adf620af7 100644
--- a/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js
+++ b/src/components/EmojiPicker/EmojiPickerMenuItem/index.native.js
@@ -1,11 +1,11 @@
-import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import getButtonState from '../../../libs/getButtonState';
-import Text from '../../Text';
-import PressableWithoutFeedback from '../../Pressable/PressableWithoutFeedback';
-import CONST from '../../../CONST';
+import React, {PureComponent} from 'react';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
const propTypes = {
/** The unicode that is used to display the emoji */
diff --git a/src/components/EmojiPicker/EmojiSkinToneList.js b/src/components/EmojiPicker/EmojiSkinToneList.js
index 0c876910e746..edb8bf49e77f 100644
--- a/src/components/EmojiPicker/EmojiSkinToneList.js
+++ b/src/components/EmojiPicker/EmojiSkinToneList.js
@@ -1,15 +1,15 @@
-import _ from 'underscore';
-import React, {useState, useCallback} from 'react';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import * as Emojis from '../../../assets/emojis';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import Text from '../Text';
+import React, {useCallback, useState} from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import * as Emojis from '@assets/emojis';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import EmojiPickerMenuItem from './EmojiPickerMenuItem';
import getSkinToneEmojiFromIndex from './getSkinToneEmojiFromIndex';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import CONST from '../../CONST';
const propTypes = {
/** Stores user's preferred skin tone */
diff --git a/src/components/EmojiPicker/getSkinToneEmojiFromIndex.js b/src/components/EmojiPicker/getSkinToneEmojiFromIndex.js
index 1b0731876f4e..48f9e2177a73 100644
--- a/src/components/EmojiPicker/getSkinToneEmojiFromIndex.js
+++ b/src/components/EmojiPicker/getSkinToneEmojiFromIndex.js
@@ -1,5 +1,5 @@
import _ from 'underscore';
-import * as Emojis from '../../../assets/emojis';
+import * as Emojis from '@assets/emojis';
/**
* Fetch the emoji code of selected skinTone
diff --git a/src/components/EmojiSuggestions.js b/src/components/EmojiSuggestions.js
index d7f7a8d6091a..2a15cfba995e 100644
--- a/src/components/EmojiSuggestions.js
+++ b/src/components/EmojiSuggestions.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import * as EmojiUtils from '../libs/EmojiUtils';
-import Text from './Text';
-import getStyledTextArray from '../libs/GetStyledTextArray';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import getStyledTextArray from '@libs/GetStyledTextArray';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
+import Text from './Text';
const propTypes = {
/** The index of the highlighted emoji */
diff --git a/src/components/EnvironmentBadge.js b/src/components/EnvironmentBadge.js
index a83fcedfabe4..a9236fc50abe 100644
--- a/src/components/EnvironmentBadge.js
+++ b/src/components/EnvironmentBadge.js
@@ -1,10 +1,10 @@
import React from 'react';
-import CONST from '../CONST';
-import Badge from './Badge';
-import styles from '../styles/styles';
-import * as Environment from '../libs/Environment/Environment';
+import useEnvironment from '@hooks/useEnvironment';
+import * as Environment from '@libs/Environment/Environment';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import pkg from '../../package.json';
-import useEnvironment from '../hooks/useEnvironment';
+import Badge from './Badge';
const ENVIRONMENT_SHORT_FORM = {
[CONST.ENVIRONMENT.DEV]: 'DEV',
diff --git a/src/components/ErrorBoundary/BaseErrorBoundary.js b/src/components/ErrorBoundary/BaseErrorBoundary.js
index d626442e81dd..b532ca23b61b 100644
--- a/src/components/ErrorBoundary/BaseErrorBoundary.js
+++ b/src/components/ErrorBoundary/BaseErrorBoundary.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {ErrorBoundary} from 'react-error-boundary';
-import BootSplash from '../../libs/BootSplash';
-import GenericErrorPage from '../../pages/ErrorPage/GenericErrorPage';
+import BootSplash from '@libs/BootSplash';
+import GenericErrorPage from '@pages/ErrorPage/GenericErrorPage';
const propTypes = {
/* A message posted to `logError` (along with error data) when this component intercepts an error */
diff --git a/src/components/ErrorBoundary/index.js b/src/components/ErrorBoundary/index.js
index 4a113fa040dd..c5498eb6f080 100644
--- a/src/components/ErrorBoundary/index.js
+++ b/src/components/ErrorBoundary/index.js
@@ -1,5 +1,5 @@
+import Log from '@libs/Log';
import BaseErrorBoundary from './BaseErrorBoundary';
-import Log from '../../libs/Log';
BaseErrorBoundary.defaultProps.logError = (errorMessage, error, errorInfo) => {
// Log the error to the server
diff --git a/src/components/ErrorBoundary/index.native.js b/src/components/ErrorBoundary/index.native.js
index 68815acf670f..a7f6a68bb01f 100644
--- a/src/components/ErrorBoundary/index.native.js
+++ b/src/components/ErrorBoundary/index.native.js
@@ -1,7 +1,6 @@
import crashlytics from '@react-native-firebase/crashlytics';
-
+import Log from '@libs/Log';
import BaseErrorBoundary from './BaseErrorBoundary';
-import Log from '../../libs/Log';
BaseErrorBoundary.defaultProps.logError = (errorMessage, error, errorInfo) => {
// Log the error to the server
diff --git a/src/components/ExceededCommentLength.js b/src/components/ExceededCommentLength.js
index 9c785cec0395..43589be566ff 100644
--- a/src/components/ExceededCommentLength.js
+++ b/src/components/ExceededCommentLength.js
@@ -1,13 +1,13 @@
-import React, {useEffect, useState, useMemo} from 'react';
-import PropTypes from 'prop-types';
import {debounce} from 'lodash';
+import PropTypes from 'prop-types';
+import React, {useEffect, useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../CONST';
-import * as ReportUtils from '../libs/ReportUtils';
-import useLocalize from '../hooks/useLocalize';
+import useLocalize from '@hooks/useLocalize';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import Text from './Text';
-import styles from '../styles/styles';
-import ONYXKEYS from '../ONYXKEYS';
const propTypes = {
/** Report ID to get the comment from (used in withOnyx) */
diff --git a/src/components/ExpensifyCashLogo.js b/src/components/ExpensifyCashLogo.js
deleted file mode 100644
index e9f2fe244eca..000000000000
--- a/src/components/ExpensifyCashLogo.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react';
-import PropTypes from 'prop-types';
-import ProductionLogo from '../../assets/images/new-expensify.svg';
-import DevLogo from '../../assets/images/new-expensify-dev.svg';
-import StagingLogo from '../../assets/images/new-expensify-stg.svg';
-import AdhocLogo from '../../assets/images/new-expensify-adhoc.svg';
-import CONST from '../CONST';
-import useEnvironment from '../hooks/useEnvironment';
-
-const propTypes = {
- /** Width of logo */
- width: PropTypes.number.isRequired,
-
- /** Height of logo */
- height: PropTypes.number.isRequired,
-};
-
-const logoComponents = {
- [CONST.ENVIRONMENT.DEV]: DevLogo,
- [CONST.ENVIRONMENT.STAGING]: StagingLogo,
- [CONST.ENVIRONMENT.PRODUCTION]: ProductionLogo,
- [CONST.ENVIRONMENT.ADHOC]: AdhocLogo,
-};
-
-function ExpensifyCashLogo(props) {
- const {environment} = useEnvironment();
-
- // PascalCase is required for React components, so capitalize the const here
- const LogoComponent = logoComponents[environment];
- return (
-
- );
-}
-
-ExpensifyCashLogo.displayName = 'ExpensifyCashLogo';
-ExpensifyCashLogo.propTypes = propTypes;
-export default ExpensifyCashLogo;
diff --git a/src/components/ExpensifyWordmark.js b/src/components/ExpensifyWordmark.js
index dde792e87e22..1fe6aee91e67 100644
--- a/src/components/ExpensifyWordmark.js
+++ b/src/components/ExpensifyWordmark.js
@@ -1,18 +1,18 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import ProductionLogo from '../../assets/images/expensify-wordmark.svg';
-import DevLogo from '../../assets/images/expensify-logo--dev.svg';
-import StagingLogo from '../../assets/images/expensify-logo--staging.svg';
-import AdHocLogo from '../../assets/images/expensify-logo--adhoc.svg';
-import CONST from '../CONST';
+import AdHocLogo from '@assets/images/expensify-logo--adhoc.svg';
+import DevLogo from '@assets/images/expensify-logo--dev.svg';
+import StagingLogo from '@assets/images/expensify-logo--staging.svg';
+import ProductionLogo from '@assets/images/expensify-wordmark.svg';
+import useEnvironment from '@hooks/useEnvironment';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-import themeColors from '../styles/themes/default';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import variables from '../styles/variables';
-import useEnvironment from '../hooks/useEnvironment';
const propTypes = {
/** Additional styles to add to the component */
diff --git a/src/components/FeatureList.js b/src/components/FeatureList.js
index 3e468abea8cc..94bb309edc84 100644
--- a/src/components/FeatureList.js
+++ b/src/components/FeatureList.js
@@ -1,11 +1,11 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import menuItemPropTypes from './menuItemPropTypes';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
import MenuItem from './MenuItem';
-import styles from '../styles/styles';
-import useLocalize from '../hooks/useLocalize';
+import menuItemPropTypes from './menuItemPropTypes';
import Text from './Text';
const propTypes = {
diff --git a/src/components/FixedFooter.tsx b/src/components/FixedFooter.tsx
index c44b9bf3d0e0..afda41f16d06 100644
--- a/src/components/FixedFooter.tsx
+++ b/src/components/FixedFooter.tsx
@@ -1,6 +1,6 @@
import React, {ReactNode} from 'react';
import {StyleProp, View, ViewStyle} from 'react-native';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
type FixedFooterProps = {
/** Children to wrap in FixedFooter. */
diff --git a/src/components/FlatList/index.android.js b/src/components/FlatList/index.android.js
index 8763488cf180..fdb3a24667aa 100644
--- a/src/components/FlatList/index.android.js
+++ b/src/components/FlatList/index.android.js
@@ -1,7 +1,7 @@
+import {useFocusEffect} from '@react-navigation/native';
+import PropTypes from 'prop-types';
import React, {forwardRef, useCallback, useState} from 'react';
import {FlatList} from 'react-native';
-import PropTypes from 'prop-types';
-import {useFocusEffect} from '@react-navigation/native';
const propTypes = {
/** Same as for FlatList */
@@ -65,10 +65,14 @@ function CustomFlatList(props) {
CustomFlatList.propTypes = propTypes;
CustomFlatList.defaultProps = defaultProps;
-export default forwardRef((props, ref) => (
+const CustomFlatListWithRef = forwardRef((props, ref) => (
));
+
+CustomFlatListWithRef.displayName = 'CustomFlatListWithRef';
+
+export default CustomFlatListWithRef;
diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js
index ef97cd1822a2..22f88cc53f59 100644
--- a/src/components/FloatingActionButton.js
+++ b/src/components/FloatingActionButton.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import {Animated, Easing, View} from 'react-native';
-import PropTypes from 'prop-types';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import themeColors from '../styles/themes/default';
+import PressableWithFeedback from './Pressable/PressableWithFeedback';
import Tooltip from './Tooltip/PopoverAnchorTooltip';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import PressableWithFeedback from './Pressable/PressableWithFeedback';
-import variables from '../styles/variables';
const AnimatedIcon = Animated.createAnimatedComponent(Icon);
AnimatedIcon.displayName = 'AnimatedIcon';
@@ -118,10 +118,14 @@ FloatingActionButton.defaultProps = defaultProps;
const FloatingActionButtonWithLocalize = withLocalize(FloatingActionButton);
-export default React.forwardRef((props, ref) => (
+const FloatingActionButtonWithLocalizeWithRef = React.forwardRef((props, ref) => (
));
+
+FloatingActionButtonWithLocalizeWithRef.displayName = 'FloatingActionButtonWithLocalizeWithRef';
+
+export default FloatingActionButtonWithLocalizeWithRef;
diff --git a/src/components/Form.js b/src/components/Form.js
index b4e639dcf964..4d3acf754715 100644
--- a/src/components/Form.js
+++ b/src/components/Form.js
@@ -1,23 +1,23 @@
-import React, {useState, useEffect, useCallback, useMemo, useRef} from 'react';
import lodashGet from 'lodash/get';
-import {Keyboard, ScrollView, StyleSheet} from 'react-native';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {Keyboard, ScrollView, StyleSheet} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import compose from '../libs/compose';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import * as FormActions from '../libs/actions/FormActions';
-import * as ErrorUtils from '../libs/ErrorUtils';
-import styles from '../styles/styles';
-import CONST from '../CONST';
+import _ from 'underscore';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Visibility from '@libs/Visibility';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as FormActions from '@userActions/FormActions';
+import CONST from '@src/CONST';
import FormAlertWithSubmitButton from './FormAlertWithSubmitButton';
import FormSubmit from './FormSubmit';
+import networkPropTypes from './networkPropTypes';
+import {withNetwork} from './OnyxProvider';
import SafeAreaConsumer from './SafeAreaConsumer';
import ScrollViewWithContext from './ScrollViewWithContext';
-import stylePropTypes from '../styles/stylePropTypes';
-import {withNetwork} from './OnyxProvider';
-import networkPropTypes from './networkPropTypes';
-import Visibility from '../libs/Visibility';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** A unique Onyx key identifying the form */
@@ -108,7 +108,7 @@ const defaultProps = {
function Form(props) {
const [errors, setErrors] = useState({});
- const [inputValues, setInputValues] = useState({...props.draftValues});
+ const [inputValues, setInputValues] = useState(() => ({...props.draftValues}));
const formRef = useRef(null);
const formContentRef = useRef(null);
const inputRefs = useRef({});
diff --git a/src/components/Form/FormProvider.js b/src/components/Form/FormProvider.js
index add58dbef18c..92baa9727832 100644
--- a/src/components/Form/FormProvider.js
+++ b/src/components/Form/FormProvider.js
@@ -1,17 +1,17 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {createRef, useCallback, useMemo, useRef, useState} from 'react';
-import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import Visibility from '../../libs/Visibility';
-import * as FormActions from '../../libs/actions/FormActions';
+import _ from 'underscore';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import compose from '@libs/compose';
+import Visibility from '@libs/Visibility';
+import stylePropTypes from '@styles/stylePropTypes';
+import * as FormActions from '@userActions/FormActions';
+import CONST from '@src/CONST';
import FormContext from './FormContext';
import FormWrapper from './FormWrapper';
-import compose from '../../libs/compose';
-import {withNetwork} from '../OnyxProvider';
-import stylePropTypes from '../../styles/stylePropTypes';
-import networkPropTypes from '../networkPropTypes';
-import CONST from '../../CONST';
const propTypes = {
/** A unique Onyx key identifying the form */
@@ -231,7 +231,13 @@ function FormProvider({validate, formID, shouldValidateOnBlur, shouldValidateOnC
return {
...propsToParse,
- ref: newRef,
+ ref:
+ typeof propsToParse.ref === 'function'
+ ? (node) => {
+ propsToParse.ref(node);
+ newRef.current = node;
+ }
+ : newRef,
inputID,
key: propsToParse.key || inputID,
errorText: errors[inputID] || fieldErrorMessage,
diff --git a/src/components/Form/FormWrapper.js b/src/components/Form/FormWrapper.js
index 82e70b68b3f0..55abcc1fc923 100644
--- a/src/components/Form/FormWrapper.js
+++ b/src/components/Form/FormWrapper.js
@@ -1,16 +1,15 @@
+import PropTypes from 'prop-types';
import React, {useCallback, useMemo, useRef} from 'react';
import {Keyboard, ScrollView, StyleSheet} from 'react-native';
-import _ from 'underscore';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import * as ErrorUtils from '../../libs/ErrorUtils';
-import FormSubmit from '../FormSubmit';
-import FormAlertWithSubmitButton from '../FormAlertWithSubmitButton';
-import styles from '../../styles/styles';
-import SafeAreaConsumer from '../SafeAreaConsumer';
-import ScrollViewWithContext from '../ScrollViewWithContext';
-
-import stylePropTypes from '../../styles/stylePropTypes';
+import _ from 'underscore';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import FormSubmit from '@components/FormSubmit';
+import SafeAreaConsumer from '@components/SafeAreaConsumer';
+import ScrollViewWithContext from '@components/ScrollViewWithContext';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
import errorsPropType from './errorsPropType';
const propTypes = {
diff --git a/src/components/Form/InputWrapper.js b/src/components/Form/InputWrapper.js
index 43064b5a6690..99237fd8db43 100644
--- a/src/components/Form/InputWrapper.js
+++ b/src/components/Form/InputWrapper.js
@@ -1,5 +1,5 @@
-import React, {forwardRef, useContext} from 'react';
import PropTypes from 'prop-types';
+import React, {forwardRef, useContext} from 'react';
import FormContext from './FormContext';
const propTypes = {
@@ -25,10 +25,14 @@ InputWrapper.propTypes = propTypes;
InputWrapper.defaultProps = defaultProps;
InputWrapper.displayName = 'InputWrapper';
-export default forwardRef((props, ref) => (
+const InputWrapperWithRef = forwardRef((props, ref) => (
));
+
+InputWrapperWithRef.displayName = 'InputWrapperWithRef';
+
+export default InputWrapperWithRef;
diff --git a/src/components/FormAlertWithSubmitButton.js b/src/components/FormAlertWithSubmitButton.js
index 33d188719d11..1ffbf0d667e2 100644
--- a/src/components/FormAlertWithSubmitButton.js
+++ b/src/components/FormAlertWithSubmitButton.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
import Button from './Button';
import FormAlertWrapper from './FormAlertWrapper';
diff --git a/src/components/FormAlertWrapper.js b/src/components/FormAlertWrapper.js
index 67e031ce6ab6..87304ee5dc3e 100644
--- a/src/components/FormAlertWrapper.js
+++ b/src/components/FormAlertWrapper.js
@@ -1,16 +1,16 @@
-import _ from 'underscore';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
import React from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import FormHelpMessage from './FormHelpMessage';
+import networkPropTypes from './networkPropTypes';
import {withNetwork} from './OnyxProvider';
import RenderHTML from './RenderHTML';
import Text from './Text';
import TextLink from './TextLink';
-import compose from '../libs/compose';
-import networkPropTypes from './networkPropTypes';
-import styles from '../styles/styles';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import FormHelpMessage from './FormHelpMessage';
const propTypes = {
/** Wrapped child components */
diff --git a/src/components/FormElement.js b/src/components/FormElement.js
index f46b24708c4c..cc9423a6147f 100644
--- a/src/components/FormElement.js
+++ b/src/components/FormElement.js
@@ -1,6 +1,6 @@
import React, {forwardRef} from 'react';
import {View} from 'react-native';
-import * as ComponentUtils from '../libs/ComponentUtils';
+import * as ComponentUtils from '@libs/ComponentUtils';
const FormElement = forwardRef((props, ref) => (
(
-
- {props.children}
-
-));
-
-FormScrollView.propTypes = propTypes;
-export default FormScrollView;
diff --git a/src/components/FormScrollView.tsx b/src/components/FormScrollView.tsx
new file mode 100644
index 000000000000..e47d75f4fb26
--- /dev/null
+++ b/src/components/FormScrollView.tsx
@@ -0,0 +1,27 @@
+import React, {ForwardedRef} from 'react';
+import {ScrollView, ScrollViewProps} from 'react-native';
+import styles from '@styles/styles';
+
+type FormScrollViewProps = ScrollViewProps & {
+ /** Form elements */
+ children: React.ReactNode;
+};
+
+function FormScrollView({children, ...rest}: FormScrollViewProps, ref: ForwardedRef) {
+ return (
+
+ {children}
+
+ );
+}
+
+FormScrollView.displayName = 'FormScrollView';
+
+export default React.forwardRef(FormScrollView);
diff --git a/src/components/FormSubmit/formSubmitPropTypes.js b/src/components/FormSubmit/formSubmitPropTypes.js
index 9a133615176f..306b3544cc11 100644
--- a/src/components/FormSubmit/formSubmitPropTypes.js
+++ b/src/components/FormSubmit/formSubmitPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import stylePropTypes from '../../styles/stylePropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
const propTypes = {
/** A reference forwarded to the inner View */
diff --git a/src/components/FormSubmit/index.js b/src/components/FormSubmit/index.js
index 7f76f77fe549..940f3638ffb1 100644
--- a/src/components/FormSubmit/index.js
+++ b/src/components/FormSubmit/index.js
@@ -1,10 +1,10 @@
-import React, {useEffect} from 'react';
import lodashGet from 'lodash/get';
+import React, {useEffect} from 'react';
import {View} from 'react-native';
+import * as ComponentUtils from '@libs/ComponentUtils';
+import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition';
+import CONST from '@src/CONST';
import * as formSubmitPropTypes from './formSubmitPropTypes';
-import CONST from '../../CONST';
-import isEnterWhileComposition from '../../libs/KeyboardShortcut/isEnterWhileComposition';
-import * as ComponentUtils from '../../libs/ComponentUtils';
function FormSubmit({innerRef, children, onSubmit, style}) {
/**
@@ -75,10 +75,14 @@ function FormSubmit({innerRef, children, onSubmit, style}) {
FormSubmit.propTypes = formSubmitPropTypes.propTypes;
FormSubmit.defaultProps = formSubmitPropTypes.defaultProps;
-export default React.forwardRef((props, ref) => (
+const FormSubmitWithRef = React.forwardRef((props, ref) => (
));
+
+FormSubmitWithRef.displayName = 'FormSubmitWithRef';
+
+export default FormSubmitWithRef;
diff --git a/src/components/FullscreenLoadingIndicator.js b/src/components/FullscreenLoadingIndicator.js
index 5c212b6dc29e..42be33ef3843 100644
--- a/src/components/FullscreenLoadingIndicator.js
+++ b/src/components/FullscreenLoadingIndicator.js
@@ -1,9 +1,9 @@
-import _ from 'underscore';
import React from 'react';
import {ActivityIndicator, StyleSheet, View} from 'react-native';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import stylePropTypes from '../styles/stylePropTypes';
+import _ from 'underscore';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
const propTypes = {
/** Additional style props */
diff --git a/src/components/GrowlNotification/GrowlNotificationContainer/growlNotificationContainerPropTypes.js b/src/components/GrowlNotification/GrowlNotificationContainer/growlNotificationContainerPropTypes.js
index 0dbdc6312c2f..2432d1b1748c 100644
--- a/src/components/GrowlNotification/GrowlNotificationContainer/growlNotificationContainerPropTypes.js
+++ b/src/components/GrowlNotification/GrowlNotificationContainer/growlNotificationContainerPropTypes.js
@@ -1,5 +1,5 @@
-import {Animated} from 'react-native';
import PropTypes from 'prop-types';
+import {Animated} from 'react-native';
const propTypes = {
/** GrowlNotification content */
diff --git a/src/components/GrowlNotification/GrowlNotificationContainer/index.js b/src/components/GrowlNotification/GrowlNotificationContainer/index.js
index 477448ffbcdc..c6614e371b6d 100644
--- a/src/components/GrowlNotification/GrowlNotificationContainer/index.js
+++ b/src/components/GrowlNotification/GrowlNotificationContainer/index.js
@@ -1,7 +1,7 @@
import React from 'react';
import {Animated} from 'react-native';
-import styles from '../../../styles/styles';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../withWindowDimensions';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import styles from '@styles/styles';
import growlNotificationContainerPropTypes from './growlNotificationContainerPropTypes';
const propTypes = {
diff --git a/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js b/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js
index ddc3636ed15b..32a8f728459c 100644
--- a/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js
+++ b/src/components/GrowlNotification/GrowlNotificationContainer/index.native.js
@@ -1,8 +1,8 @@
import React from 'react';
import {Animated} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
-import styles from '../../../styles/styles';
-import * as StyleUtils from '../../../styles/StyleUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import growlNotificationContainerPropTypes from './growlNotificationContainerPropTypes';
const propTypes = {
diff --git a/src/components/GrowlNotification/index.js b/src/components/GrowlNotification/index.js
index a06185ac3320..5fdbe205f87b 100644
--- a/src/components/GrowlNotification/index.js
+++ b/src/components/GrowlNotification/index.js
@@ -1,16 +1,16 @@
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
+import {Animated, View} from 'react-native';
import {Directions, FlingGestureHandler, State} from 'react-native-gesture-handler';
-import {View, Animated} from 'react-native';
-import themeColors from '../../styles/themes/default';
-import Text from '../Text';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import styles from '../../styles/styles';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Pressables from '@components/Pressable';
+import Text from '@components/Text';
+import * as Growl from '@libs/Growl';
+import useNativeDriver from '@libs/useNativeDriver';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import GrowlNotificationContainer from './GrowlNotificationContainer';
-import CONST from '../../CONST';
-import * as Growl from '../../libs/Growl';
-import * as Pressables from '../Pressable';
-import useNativeDriver from '../../libs/useNativeDriver';
const types = {
[CONST.GROWL.SUCCESS]: {
diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
index 04759b89e5d0..c4eed0134008 100755
--- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
+++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
@@ -1,12 +1,12 @@
-import _ from 'underscore';
-import React, {useMemo} from 'react';
-import {TRenderEngineProvider, RenderHTMLConfigProvider, defaultHTMLElementModels} from 'react-native-render-html';
import PropTypes from 'prop-types';
-import htmlRenderers from './HTMLRenderers';
+import React, {useMemo} from 'react';
+import {defaultHTMLElementModels, RenderHTMLConfigProvider, TRenderEngineProvider} from 'react-native-render-html';
+import _ from 'underscore';
+import convertToLTR from '@libs/convertToLTR';
+import singleFontFamily from '@styles/fontFamily/singleFontFamily';
+import styles from '@styles/styles';
import * as HTMLEngineUtils from './htmlEngineUtils';
-import styles from '../../styles/styles';
-import convertToLTR from '../../libs/convertToLTR';
-import singleFontFamily from '../../styles/fontFamily/singleFontFamily';
+import htmlRenderers from './HTMLRenderers';
const propTypes = {
/** Whether text elements should be selectable */
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
index 92a313cf1e0a..be70af0adb4f 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/AnchorRenderer.js
@@ -1,20 +1,20 @@
+import lodashGet from 'lodash/get';
import React from 'react';
import {TNodeChildrenRenderer} from 'react-native-render-html';
-import lodashGet from 'lodash/get';
+import AnchorForAttachmentsOnly from '@components/AnchorForAttachmentsOnly';
+import AnchorForCommentsOnly from '@components/AnchorForCommentsOnly';
+import * as HTMLEngineUtils from '@components/HTMLEngineProvider/htmlEngineUtils';
+import Text from '@components/Text';
+import useEnvironment from '@hooks/useEnvironment';
+import Navigation from '@libs/Navigation/Navigation';
+import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
+import * as Url from '@libs/Url';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import htmlRendererPropTypes from './htmlRendererPropTypes';
-import * as HTMLEngineUtils from '../htmlEngineUtils';
-import * as Link from '../../../libs/actions/Link';
-import CONFIG from '../../../CONFIG';
-import Text from '../../Text';
-import CONST from '../../../CONST';
-import styles from '../../../styles/styles';
-import Navigation from '../../../libs/Navigation/Navigation';
-import AnchorForCommentsOnly from '../../AnchorForCommentsOnly';
-import AnchorForAttachmentsOnly from '../../AnchorForAttachmentsOnly';
-import * as Url from '../../../libs/Url';
-import ROUTES from '../../../ROUTES';
-import tryResolveUrlFromApiRoot from '../../../libs/tryResolveUrlFromApiRoot';
-import useEnvironment from '../../../hooks/useEnvironment';
function AnchorRenderer(props) {
const htmlAttribs = props.tnode.attributes;
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/CodeRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/CodeRenderer.js
index b72725076953..8d2a825ff638 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/CodeRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/CodeRenderer.js
@@ -1,9 +1,9 @@
-import _ from 'underscore';
import React from 'react';
import {splitBoxModelStyle} from 'react-native-render-html';
+import _ from 'underscore';
+import InlineCodeBlock from '@components/InlineCodeBlock';
+import * as StyleUtils from '@styles/StyleUtils';
import htmlRendererPropTypes from './htmlRendererPropTypes';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import InlineCodeBlock from '../../InlineCodeBlock';
function CodeRenderer(props) {
// We split wrapper and inner styles
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js
index a0b6b0dadf9f..ab8e88cf088a 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/EditedRenderer.js
@@ -1,13 +1,13 @@
-import _ from 'underscore';
import React from 'react';
-import CONST from '../../../CONST';
+import _ from 'underscore';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import editedLabelStyles from '@styles/editedLabelStyles';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import htmlRendererPropTypes from './htmlRendererPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
-import Text from '../../Text';
-import variables from '../../../styles/variables';
-import themeColors from '../../../styles/themes/default';
-import styles from '../../../styles/styles';
-import editedLabelStyles from '../../../styles/editedLabelStyles';
const propTypes = {
...htmlRendererPropTypes,
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js
index f5fac7b49e0f..f6d37f661252 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/ImageRenderer.js
@@ -1,18 +1,18 @@
+import lodashGet from 'lodash/get';
import React, {memo} from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import Navigation from '../../../libs/Navigation/Navigation';
+import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
+import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
+import ThumbnailImage from '@components/ThumbnailImage';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import htmlRendererPropTypes from './htmlRendererPropTypes';
-import styles from '../../../styles/styles';
-import ThumbnailImage from '../../ThumbnailImage';
-import PressableWithoutFocus from '../../Pressable/PressableWithoutFocus';
-import CONST from '../../../CONST';
-import {ShowContextMenuContext, showContextMenuForReport} from '../../ShowContextMenuContext';
-import tryResolveUrlFromApiRoot from '../../../libs/tryResolveUrlFromApiRoot';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import ROUTES from '../../../ROUTES';
-import ONYXKEYS from '../../../ONYXKEYS';
-import useLocalize from '../../../hooks/useLocalize';
const propTypes = {...htmlRendererPropTypes};
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionHereRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/MentionHereRenderer.js
index 35ace6814703..eb238ec0dd7d 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionHereRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionHereRenderer.js
@@ -1,9 +1,9 @@
import React from 'react';
-import _ from 'underscore';
import {TNodeChildrenRenderer} from 'react-native-render-html';
+import _ from 'underscore';
+import Text from '@components/Text';
+import * as StyleUtils from '@styles/StyleUtils';
import htmlRendererPropTypes from './htmlRendererPropTypes';
-import Text from '../../Text';
-import * as StyleUtils from '../../../styles/StyleUtils';
function MentionHereRenderer(props) {
return (
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
index 812f4e951f74..b7b7c43e7b58 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/MentionUserRenderer.js
@@ -1,22 +1,25 @@
+import lodashGet from 'lodash/get';
import React from 'react';
-import _ from 'underscore';
-import {TNodeChildrenRenderer} from 'react-native-render-html';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import Text from '../../Text';
-import UserDetailsTooltip from '../../UserDetailsTooltip';
+import {TNodeChildrenRenderer} from 'react-native-render-html';
+import _ from 'underscore';
+import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
+import Text from '@components/Text';
+import UserDetailsTooltip from '@components/UserDetailsTooltip';
+import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import htmlRendererPropTypes from './htmlRendererPropTypes';
-import withCurrentUserPersonalDetails from '../../withCurrentUserPersonalDetails';
-import personalDetailsPropType from '../../../pages/personalDetailsPropType';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import * as PersonalDetailsUtils from '../../../libs/PersonalDetailsUtils';
-import compose from '../../../libs/compose';
-import TextLink from '../../TextLink';
-import ONYXKEYS from '../../../ONYXKEYS';
-import useLocalize from '../../../hooks/useLocalize';
-import CONST from '../../../CONST';
const propTypes = {
...htmlRendererPropTypes,
@@ -40,7 +43,7 @@ function MentionUserRenderer(props) {
if (!_.isEmpty(htmlAttribAccountID)) {
const user = lodashGet(props.personalDetails, htmlAttribAccountID);
accountID = parseInt(htmlAttribAccountID, 10);
- displayNameOrLogin = lodashGet(user, 'login', '') || lodashGet(user, 'displayName', '') || translate('common.hidden');
+ displayNameOrLogin = LocalePhoneNumber.formatPhoneNumber(lodashGet(user, 'login', '')) || lodashGet(user, 'displayName', '') || translate('common.hidden');
navigationRoute = ROUTES.PROFILE.getRoute(htmlAttribAccountID);
} else if (!_.isEmpty(props.tnode.data)) {
// We need to remove the LTR unicode and leading @ from data as it is not part of the login
@@ -56,26 +59,38 @@ function MentionUserRenderer(props) {
const isOurMention = accountID === props.currentUserPersonalDetails.accountID;
return (
-
-
- Navigation.navigate(navigationRoute)}
- // Add testID so it is NOT selected as an anchor tag by SelectionScraper
- testID="span"
+
+ {({anchor, report, action, checkIfContextMenuActive}) => (
+ showContextMenuForReport(event, anchor, report.reportID, action, checkIfContextMenuActive, ReportUtils.isArchivedRoom(report))}
+ onPress={(event) => {
+ event.preventDefault();
+ Navigation.navigate(navigationRoute);
+ }}
+ accessibilityRole={CONST.ACCESSIBILITY_ROLE.LINK}
+ accessibilityLabel={`/${navigationRoute}`}
>
- {!_.isEmpty(htmlAttribAccountID) ? `@${displayNameOrLogin}` : }
-
-
-
+
+
+ {!_.isEmpty(htmlAttribAccountID) ? `@${displayNameOrLogin}` : }
+
+
+
+ )}
+
);
}
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
index 78e7c1172c05..53d365d257a2 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/BasePreRenderer.js
@@ -1,14 +1,14 @@
-import React, {forwardRef} from 'react';
-import {View, ScrollView} from 'react-native';
import PropTypes from 'prop-types';
+import React, {forwardRef} from 'react';
+import {ScrollView, View} from 'react-native';
import _ from 'underscore';
-import htmlRendererPropTypes from '../htmlRendererPropTypes';
-import withLocalize from '../../../withLocalize';
-import {ShowContextMenuContext, showContextMenuForReport} from '../../../ShowContextMenuContext';
-import styles from '../../../../styles/styles';
-import * as ReportUtils from '../../../../libs/ReportUtils';
-import PressableWithoutFeedback from '../../../Pressable/PressableWithoutFeedback';
-import CONST from '../../../../CONST';
+import htmlRendererPropTypes from '@components/HTMLEngineProvider/HTMLRenderers/htmlRendererPropTypes';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import {ShowContextMenuContext, showContextMenuForReport} from '@components/ShowContextMenuContext';
+import withLocalize from '@components/withLocalize';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Press in handler for the code block */
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js
index 782ad82f643c..ed6d275201ec 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.js
@@ -1,11 +1,12 @@
import React, {useCallback, useEffect, useRef} from 'react';
import _ from 'underscore';
-
-import ControlSelection from '../../../../libs/ControlSelection';
-import * as DeviceCapabilities from '../../../../libs/DeviceCapabilities';
-import htmlRendererPropTypes from '../htmlRendererPropTypes';
+import htmlRendererPropTypes from '@components/HTMLEngineProvider/HTMLRenderers/htmlRendererPropTypes';
+import ControlSelection from '@libs/ControlSelection';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import BasePreRenderer from './BasePreRenderer';
+const supportsPassive = DeviceCapabilities.hasPassiveEventListenerSupport();
+
const isScrollingVertically = (event) =>
// Mark as vertical scrolling only when absolute value of deltaY is more than the double of absolute
// value of deltaX, so user can use trackpad scroll on the code block horizontally at a wide angle.
@@ -32,7 +33,6 @@ function PreRenderer(props) {
const horizontalOverflow = node.scrollWidth > node.offsetWidth;
if (event.currentTarget === node && horizontalOverflow && !debouncedIsScrollingVertically(event)) {
node.scrollLeft += event.deltaX;
- event.preventDefault();
event.stopPropagation();
}
}, []);
@@ -42,7 +42,7 @@ function PreRenderer(props) {
if (!eventListenerRefValue) {
return;
}
- eventListenerRefValue.getScrollableNode().addEventListener('wheel', scrollNode);
+ eventListenerRefValue.getScrollableNode().addEventListener('wheel', scrollNode, supportsPassive ? {passive: true} : false);
return () => {
if (!eventListenerRefValue.getScrollableNode()) {
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.native.js b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.native.js
index 385f396de812..b84dd43dd82f 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.native.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/PreRenderer/index.native.js
@@ -1,6 +1,6 @@
import React from 'react';
-import withLocalize from '../../../withLocalize';
-import htmlRendererPropTypes from '../htmlRendererPropTypes';
+import htmlRendererPropTypes from '@components/HTMLEngineProvider/HTMLRenderers/htmlRendererPropTypes';
+import withLocalize from '@components/withLocalize';
import BasePreRenderer from './BasePreRenderer';
function PreRenderer(props) {
diff --git a/src/components/HTMLEngineProvider/HTMLRenderers/index.js b/src/components/HTMLEngineProvider/HTMLRenderers/index.js
index a866d86486b6..69f8eeac798e 100644
--- a/src/components/HTMLEngineProvider/HTMLRenderers/index.js
+++ b/src/components/HTMLEngineProvider/HTMLRenderers/index.js
@@ -1,8 +1,8 @@
import AnchorRenderer from './AnchorRenderer';
import CodeRenderer from './CodeRenderer';
import EditedRenderer from './EditedRenderer';
-import MentionHereRenderer from './MentionHereRenderer';
import ImageRenderer from './ImageRenderer';
+import MentionHereRenderer from './MentionHereRenderer';
import MentionUserRenderer from './MentionUserRenderer';
import PreRenderer from './PreRenderer';
diff --git a/src/components/HTMLEngineProvider/index.js b/src/components/HTMLEngineProvider/index.js
index 6cb08a6dfe97..8a8e96269411 100755
--- a/src/components/HTMLEngineProvider/index.js
+++ b/src/components/HTMLEngineProvider/index.js
@@ -1,8 +1,8 @@
import React from 'react';
+import withWindowDimensions from '@components/withWindowDimensions';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import BaseHTMLEngineProvider from './BaseHTMLEngineProvider';
import {defaultProps, propTypes} from './htmlEnginePropTypes';
-import withWindowDimensions from '../withWindowDimensions';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
function HTMLEngineProvider(props) {
return (
diff --git a/src/components/HTMLEngineProvider/index.native.js b/src/components/HTMLEngineProvider/index.native.js
index 162edda66f1f..f760a5a36649 100755
--- a/src/components/HTMLEngineProvider/index.native.js
+++ b/src/components/HTMLEngineProvider/index.native.js
@@ -1,6 +1,6 @@
import React from 'react';
import BaseHTMLEngineProvider from './BaseHTMLEngineProvider';
-import {propTypes, defaultProps} from './htmlEnginePropTypes';
+import {defaultProps, propTypes} from './htmlEnginePropTypes';
function HTMLEngineProvider(props) {
return (
diff --git a/src/components/Header.js b/src/components/Header.js
index a54ef93db804..65bf703e6037 100644
--- a/src/components/Header.js
+++ b/src/components/Header.js
@@ -1,10 +1,10 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import styles from '../styles/styles';
-import Text from './Text';
+import styles from '@styles/styles';
import EnvironmentBadge from './EnvironmentBadge';
+import Text from './Text';
const propTypes = {
/** Title of the Header */
diff --git a/src/components/HeaderGap/index.desktop.js b/src/components/HeaderGap/index.desktop.js
index 6b47f56516de..02918fbe3a51 100644
--- a/src/components/HeaderGap/index.desktop.js
+++ b/src/components/HeaderGap/index.desktop.js
@@ -1,7 +1,7 @@
+import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
+import styles from '@styles/styles';
const propTypes = {
/** Styles to apply to the HeaderGap */
diff --git a/src/components/HeaderPageLayout.js b/src/components/HeaderPageLayout.js
index adfe0a8784e2..daacf197a672 100644
--- a/src/components/HeaderPageLayout.js
+++ b/src/components/HeaderPageLayout.js
@@ -1,17 +1,17 @@
-import _ from 'underscore';
-import React, {useMemo} from 'react';
import PropTypes from 'prop-types';
+import React, {useMemo} from 'react';
import {ScrollView, View} from 'react-native';
-import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
+import _ from 'underscore';
+import useNetwork from '@hooks/useNetwork';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import FixedFooter from './FixedFooter';
import HeaderWithBackButton from './HeaderWithBackButton';
+import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
import ScreenWrapper from './ScreenWrapper';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import * as StyleUtils from '../styles/StyleUtils';
-import useWindowDimensions from '../hooks/useWindowDimensions';
-import FixedFooter from './FixedFooter';
-import useNetwork from '../hooks/useNetwork';
-import * as Browser from '../libs/Browser';
const propTypes = {
...headerWithBackButtonPropTypes,
diff --git a/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js b/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js
index d2cdc5b29898..1ad1f0961e38 100644
--- a/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js
+++ b/src/components/HeaderWithBackButton/headerWithBackButtonPropTypes.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
-import {ThreeDotsMenuItemPropTypes} from '../ThreeDotsMenu';
-import iouReportPropTypes from '../../pages/iouReportPropTypes';
-import participantPropTypes from '../participantPropTypes';
+import participantPropTypes from '@components/participantPropTypes';
+import {ThreeDotsMenuItemPropTypes} from '@components/ThreeDotsMenu';
+import iouReportPropTypes from '@pages/iouReportPropTypes';
const propTypes = {
/** Title of the Header */
@@ -31,12 +31,18 @@ const propTypes = {
/** Whether we should show a get assistance (question mark) button */
shouldShowGetAssistanceButton: PropTypes.bool,
+ /** Whether we should disable the get assistance button */
+ shouldDisableGetAssistanceButton: PropTypes.bool,
+
/** Whether we should show a pin button */
shouldShowPinButton: PropTypes.bool,
/** Whether we should show a more options (threedots) button */
shouldShowThreeDotsButton: PropTypes.bool,
+ /** Whether we should disable threedots button */
+ shouldDisableThreeDotsButton: PropTypes.bool,
+
/** List of menu items for more(three dots) menu */
threeDotsMenuItems: ThreeDotsMenuItemPropTypes,
@@ -84,6 +90,9 @@ const propTypes = {
/** Children to wrap in Header */
children: PropTypes.node,
+
+ /** Single execution function to prevent concurrent navigation actions */
+ singleExecution: PropTypes.func,
};
export default propTypes;
diff --git a/src/components/HeaderWithBackButton/index.js b/src/components/HeaderWithBackButton/index.js
index 26febfe5745d..67e8790560dc 100755
--- a/src/components/HeaderWithBackButton/index.js
+++ b/src/components/HeaderWithBackButton/index.js
@@ -1,23 +1,24 @@
import React from 'react';
-import {View, Keyboard} from 'react-native';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import Header from '../Header';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import Tooltip from '../Tooltip';
-import getButtonState from '../../libs/getButtonState';
-import * as StyleUtils from '../../styles/StyleUtils';
-import ThreeDotsMenu from '../ThreeDotsMenu';
-import AvatarWithDisplayName from '../AvatarWithDisplayName';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import PinButton from '../PinButton';
+import {Keyboard, View} from 'react-native';
+import AvatarWithDisplayName from '@components/AvatarWithDisplayName';
+import Header from '@components/Header';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PinButton from '@components/PinButton';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import ThreeDotsMenu from '@components/ThreeDotsMenu';
+import Tooltip from '@components/Tooltip';
+import useKeyboardState from '@hooks/useKeyboardState';
+import useLocalize from '@hooks/useLocalize';
+import useThrottledButtonState from '@hooks/useThrottledButtonState';
+import useWaitForNavigation from '@hooks/useWaitForNavigation';
+import getButtonState from '@libs/getButtonState';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import headerWithBackButtonPropTypes from './headerWithBackButtonPropTypes';
-import useThrottledButtonState from '../../hooks/useThrottledButtonState';
-import useLocalize from '../../hooks/useLocalize';
-import useKeyboardState from '../../hooks/useKeyboardState';
function HeaderWithBackButton({
iconFill = undefined,
@@ -35,8 +36,10 @@ function HeaderWithBackButton({
shouldShowCloseButton = false,
shouldShowDownloadButton = false,
shouldShowGetAssistanceButton = false,
+ shouldDisableGetAssistanceButton = false,
shouldShowPinButton = false,
shouldShowThreeDotsButton = false,
+ shouldDisableThreeDotsButton = false,
stepCounter = null,
subtitle = '',
title = '',
@@ -49,12 +52,19 @@ function HeaderWithBackButton({
shouldEnableDetailPageNavigation = false,
children = null,
shouldOverlay = false,
+ singleExecution = (func) => func,
}) {
const [isDownloadButtonActive, temporarilyDisableDownloadButton] = useThrottledButtonState();
const {translate} = useLocalize();
const {isKeyboardShown} = useKeyboardState();
+ const waitForNavigate = useWaitForNavigation();
return (
-
+
{shouldShowBackButton && (
@@ -121,7 +131,8 @@ function HeaderWithBackButton({
{shouldShowGetAssistanceButton && (
Navigation.navigate(ROUTES.GET_ASSISTANCE.getRoute(guidesCallTaskID))}
+ disabled={shouldDisableGetAssistanceButton}
+ onPress={singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.GET_ASSISTANCE.getRoute(guidesCallTaskID))))}
style={[styles.touchableButtonImage]}
accessibilityRole="button"
accessibilityLabel={translate('getAssistancePage.questionMarkButtonTooltip')}
@@ -136,6 +147,7 @@ function HeaderWithBackButton({
{shouldShowPinButton && }
{shouldShowThreeDotsButton && (
{
+ ref.current = el;
+ assignRef(child.ref, el);
+ };
+
if (!DeviceCapabilities.hasHoverSupport()) {
- return child;
+ return React.cloneElement(child, {
+ ref: hijackRef,
+ });
}
return React.cloneElement(child, {
- ref: (el) => {
- ref.current = el;
- assignRef(child.ref, el);
- },
+ ref: hijackRef,
onMouseEnter: enableHoveredOnMouseEnter,
onMouseLeave: disableHoveredOnMouseLeave,
onBlur: disableHoveredOnBlur,
diff --git a/src/components/Hoverable/index.native.js b/src/components/Hoverable/index.native.js
index 26d1d98863d6..1c5df276baa6 100644
--- a/src/components/Hoverable/index.native.js
+++ b/src/components/Hoverable/index.native.js
@@ -1,7 +1,7 @@
-import _ from 'underscore';
import React from 'react';
import {View} from 'react-native';
-import {propTypes, defaultProps} from './hoverablePropTypes';
+import _ from 'underscore';
+import {defaultProps, propTypes} from './hoverablePropTypes';
/**
* On mobile, there is no concept of hovering, so we return a plain wrapper around the component's children,
diff --git a/src/components/IFrame.js b/src/components/IFrame.js
index 5f7f657b0c09..aa85ad03ffbf 100644
--- a/src/components/IFrame.js
+++ b/src/components/IFrame.js
@@ -1,8 +1,8 @@
/* eslint-disable es/no-nullish-coalescing-operators */
+import PropTypes from 'prop-types';
import React, {useEffect, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import ONYXKEYS from '../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
function getNewDotURL(url) {
const urlObj = new URL(url);
diff --git a/src/components/Icon/BankIcons.ts b/src/components/Icon/BankIcons.ts
index a30594d1ab3f..5d17e7f0c991 100644
--- a/src/components/Icon/BankIcons.ts
+++ b/src/components/Icon/BankIcons.ts
@@ -1,48 +1,48 @@
-import {SvgProps} from 'react-native-svg';
import {CSSProperties} from 'react';
import {ViewStyle} from 'react-native';
-import AmericanExpress from '../../../assets/images/bankicons/american-express.svg';
-import BankOfAmerica from '../../../assets/images/bankicons/bank-of-america.svg';
-import BB_T from '../../../assets/images/bankicons/bb-t.svg';
-import CapitalOne from '../../../assets/images/bankicons/capital-one.svg';
-import CharlesSchwab from '../../../assets/images/bankicons/charles-schwab.svg';
-import Chase from '../../../assets/images/bankicons/chase.svg';
-import CitiBank from '../../../assets/images/bankicons/citibank.svg';
-import CitizensBank from '../../../assets/images/bankicons/citizens-bank.svg';
-import Discover from '../../../assets/images/bankicons/discover.svg';
-import Fidelity from '../../../assets/images/bankicons/fidelity.svg';
-import HuntingtonBank from '../../../assets/images/bankicons/huntington-bank.svg';
-import GenericBank from '../../../assets/images/bankicons/generic-bank-account.svg';
-import NavyFederalCreditUnion from '../../../assets/images/bankicons/navy-federal-credit-union.svg';
-import PNC from '../../../assets/images/bankicons/pnc.svg';
-import RegionsBank from '../../../assets/images/bankicons/regions-bank.svg';
-import SunTrust from '../../../assets/images/bankicons/suntrust.svg';
-import TdBank from '../../../assets/images/bankicons/td-bank.svg';
-import USBank from '../../../assets/images/bankicons/us-bank.svg';
-import USAA from '../../../assets/images/bankicons/usaa.svg';
+import {SvgProps} from 'react-native-svg';
+import AmericanExpress from '@assets/images/bankicons/american-express.svg';
+import BankOfAmerica from '@assets/images/bankicons/bank-of-america.svg';
+import BB_T from '@assets/images/bankicons/bb-t.svg';
+import CapitalOne from '@assets/images/bankicons/capital-one.svg';
+import CharlesSchwab from '@assets/images/bankicons/charles-schwab.svg';
+import Chase from '@assets/images/bankicons/chase.svg';
+import CitiBank from '@assets/images/bankicons/citibank.svg';
+import CitizensBank from '@assets/images/bankicons/citizens-bank.svg';
+import Discover from '@assets/images/bankicons/discover.svg';
+import Fidelity from '@assets/images/bankicons/fidelity.svg';
+import GenericBank from '@assets/images/bankicons/generic-bank-account.svg';
+import HuntingtonBank from '@assets/images/bankicons/huntington-bank.svg';
+import NavyFederalCreditUnion from '@assets/images/bankicons/navy-federal-credit-union.svg';
+import PNC from '@assets/images/bankicons/pnc.svg';
+import RegionsBank from '@assets/images/bankicons/regions-bank.svg';
+import SunTrust from '@assets/images/bankicons/suntrust.svg';
+import TdBank from '@assets/images/bankicons/td-bank.svg';
+import USBank from '@assets/images/bankicons/us-bank.svg';
+import USAA from '@assets/images/bankicons/usaa.svg';
// Card Icons
-import AmericanExpressCard from '../../../assets/images/cardicons/american-express.svg';
-import BankOfAmericaCard from '../../../assets/images/cardicons/bank-of-america.svg';
-import BB_TCard from '../../../assets/images/cardicons/bb-t.svg';
-import CapitalOneCard from '../../../assets/images/cardicons/capital-one.svg';
-import CharlesSchwabCard from '../../../assets/images/cardicons/charles-schwab.svg';
-import ChaseCard from '../../../assets/images/cardicons/chase.svg';
-import CitiBankCard from '../../../assets/images/cardicons/citibank.svg';
-import CitizensBankCard from '../../../assets/images/cardicons/citizens.svg';
-import DiscoverCard from '../../../assets/images/cardicons/discover.svg';
-import FidelityCard from '../../../assets/images/cardicons/fidelity.svg';
-import HuntingtonBankCard from '../../../assets/images/cardicons/huntington-bank.svg';
-import GenericBankCard from '../../../assets/images/cardicons/generic-bank-card.svg';
-import NavyFederalCreditUnionCard from '../../../assets/images/cardicons/navy-federal-credit-union.svg';
-import PNCCard from '../../../assets/images/cardicons/pnc.svg';
-import RegionsBankCard from '../../../assets/images/cardicons/regions-bank.svg';
-import SunTrustCard from '../../../assets/images/cardicons/suntrust.svg';
-import TdBankCard from '../../../assets/images/cardicons/td-bank.svg';
-import USBankCard from '../../../assets/images/cardicons/us-bank.svg';
-import USAACard from '../../../assets/images/cardicons/usaa.svg';
-import ExpensifyCardImage from '../../../assets/images/cardicons/expensify-card-dark.svg';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
+import AmericanExpressCard from '@assets/images/cardicons/american-express.svg';
+import BankOfAmericaCard from '@assets/images/cardicons/bank-of-america.svg';
+import BB_TCard from '@assets/images/cardicons/bb-t.svg';
+import CapitalOneCard from '@assets/images/cardicons/capital-one.svg';
+import CharlesSchwabCard from '@assets/images/cardicons/charles-schwab.svg';
+import ChaseCard from '@assets/images/cardicons/chase.svg';
+import CitiBankCard from '@assets/images/cardicons/citibank.svg';
+import CitizensBankCard from '@assets/images/cardicons/citizens.svg';
+import DiscoverCard from '@assets/images/cardicons/discover.svg';
+import ExpensifyCardImage from '@assets/images/cardicons/expensify-card-dark.svg';
+import FidelityCard from '@assets/images/cardicons/fidelity.svg';
+import GenericBankCard from '@assets/images/cardicons/generic-bank-card.svg';
+import HuntingtonBankCard from '@assets/images/cardicons/huntington-bank.svg';
+import NavyFederalCreditUnionCard from '@assets/images/cardicons/navy-federal-credit-union.svg';
+import PNCCard from '@assets/images/cardicons/pnc.svg';
+import RegionsBankCard from '@assets/images/cardicons/regions-bank.svg';
+import SunTrustCard from '@assets/images/cardicons/suntrust.svg';
+import TdBankCard from '@assets/images/cardicons/td-bank.svg';
+import USBankCard from '@assets/images/cardicons/us-bank.svg';
+import USAACard from '@assets/images/cardicons/usaa.svg';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
type BankIcon = {
icon: React.FC;
diff --git a/src/components/Icon/DefaultAvatars.js b/src/components/Icon/DefaultAvatars.js
index 2c143f68705d..698c2ce7368c 100644
--- a/src/components/Icon/DefaultAvatars.js
+++ b/src/components/Icon/DefaultAvatars.js
@@ -1,27 +1,27 @@
-import Avatar1 from '../../../assets/images/avatars/user/default-avatar_1.svg';
-import Avatar2 from '../../../assets/images/avatars/user/default-avatar_2.svg';
-import Avatar3 from '../../../assets/images/avatars/user/default-avatar_3.svg';
-import Avatar4 from '../../../assets/images/avatars/user/default-avatar_4.svg';
-import Avatar5 from '../../../assets/images/avatars/user/default-avatar_5.svg';
-import Avatar6 from '../../../assets/images/avatars/user/default-avatar_6.svg';
-import Avatar7 from '../../../assets/images/avatars/user/default-avatar_7.svg';
-import Avatar8 from '../../../assets/images/avatars/user/default-avatar_8.svg';
-import Avatar9 from '../../../assets/images/avatars/user/default-avatar_9.svg';
-import Avatar10 from '../../../assets/images/avatars/user/default-avatar_10.svg';
-import Avatar11 from '../../../assets/images/avatars/user/default-avatar_11.svg';
-import Avatar12 from '../../../assets/images/avatars/user/default-avatar_12.svg';
-import Avatar13 from '../../../assets/images/avatars/user/default-avatar_13.svg';
-import Avatar14 from '../../../assets/images/avatars/user/default-avatar_14.svg';
-import Avatar15 from '../../../assets/images/avatars/user/default-avatar_15.svg';
-import Avatar16 from '../../../assets/images/avatars/user/default-avatar_16.svg';
-import Avatar17 from '../../../assets/images/avatars/user/default-avatar_17.svg';
-import Avatar18 from '../../../assets/images/avatars/user/default-avatar_18.svg';
-import Avatar19 from '../../../assets/images/avatars/user/default-avatar_19.svg';
-import Avatar20 from '../../../assets/images/avatars/user/default-avatar_20.svg';
-import Avatar21 from '../../../assets/images/avatars/user/default-avatar_21.svg';
-import Avatar22 from '../../../assets/images/avatars/user/default-avatar_22.svg';
-import Avatar23 from '../../../assets/images/avatars/user/default-avatar_23.svg';
-import Avatar24 from '../../../assets/images/avatars/user/default-avatar_24.svg';
+import Avatar1 from '@assets/images/avatars/user/default-avatar_1.svg';
+import Avatar2 from '@assets/images/avatars/user/default-avatar_2.svg';
+import Avatar3 from '@assets/images/avatars/user/default-avatar_3.svg';
+import Avatar4 from '@assets/images/avatars/user/default-avatar_4.svg';
+import Avatar5 from '@assets/images/avatars/user/default-avatar_5.svg';
+import Avatar6 from '@assets/images/avatars/user/default-avatar_6.svg';
+import Avatar7 from '@assets/images/avatars/user/default-avatar_7.svg';
+import Avatar8 from '@assets/images/avatars/user/default-avatar_8.svg';
+import Avatar9 from '@assets/images/avatars/user/default-avatar_9.svg';
+import Avatar10 from '@assets/images/avatars/user/default-avatar_10.svg';
+import Avatar11 from '@assets/images/avatars/user/default-avatar_11.svg';
+import Avatar12 from '@assets/images/avatars/user/default-avatar_12.svg';
+import Avatar13 from '@assets/images/avatars/user/default-avatar_13.svg';
+import Avatar14 from '@assets/images/avatars/user/default-avatar_14.svg';
+import Avatar15 from '@assets/images/avatars/user/default-avatar_15.svg';
+import Avatar16 from '@assets/images/avatars/user/default-avatar_16.svg';
+import Avatar17 from '@assets/images/avatars/user/default-avatar_17.svg';
+import Avatar18 from '@assets/images/avatars/user/default-avatar_18.svg';
+import Avatar19 from '@assets/images/avatars/user/default-avatar_19.svg';
+import Avatar20 from '@assets/images/avatars/user/default-avatar_20.svg';
+import Avatar21 from '@assets/images/avatars/user/default-avatar_21.svg';
+import Avatar22 from '@assets/images/avatars/user/default-avatar_22.svg';
+import Avatar23 from '@assets/images/avatars/user/default-avatar_23.svg';
+import Avatar24 from '@assets/images/avatars/user/default-avatar_24.svg';
export {
Avatar1,
diff --git a/src/components/Icon/EReceiptBGs.js b/src/components/Icon/EReceiptBGs.js
index ff74c0fb83c2..16c23f4a99d4 100644
--- a/src/components/Icon/EReceiptBGs.js
+++ b/src/components/Icon/EReceiptBGs.js
@@ -1,8 +1,8 @@
-import EReceiptBG_Yellow from '../../../assets/images/eReceiptBGs/eReceiptBG_yellow.png';
-import EReceiptBG_Ice from '../../../assets/images/eReceiptBGs/eReceiptBG_navy.png';
-import EReceiptBG_Blue from '../../../assets/images/eReceiptBGs/eReceiptBG_blue.png';
-import EReceiptBG_Green from '../../../assets/images/eReceiptBGs/eReceiptBG_green.png';
-import EReceiptBG_Tangerine from '../../../assets/images/eReceiptBGs/eReceiptBG_tangerine.png';
-import EReceiptBG_Pink from '../../../assets/images/eReceiptBGs/eReceiptBG_pink.png';
+import EReceiptBG_Blue from '@assets/images/eReceiptBGs/eReceiptBG_blue.png';
+import EReceiptBG_Green from '@assets/images/eReceiptBGs/eReceiptBG_green.png';
+import EReceiptBG_Ice from '@assets/images/eReceiptBGs/eReceiptBG_navy.png';
+import EReceiptBG_Pink from '@assets/images/eReceiptBGs/eReceiptBG_pink.png';
+import EReceiptBG_Tangerine from '@assets/images/eReceiptBGs/eReceiptBG_tangerine.png';
+import EReceiptBG_Yellow from '@assets/images/eReceiptBGs/eReceiptBG_yellow.png';
export {EReceiptBG_Yellow, EReceiptBG_Ice, EReceiptBG_Blue, EReceiptBG_Green, EReceiptBG_Tangerine, EReceiptBG_Pink};
diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js
index dd106c6b3c20..a4aa6b13cb29 100644
--- a/src/components/Icon/Expensicons.js
+++ b/src/components/Icon/Expensicons.js
@@ -1,130 +1,132 @@
-import ActiveRoomAvatar from '../../../assets/images/avatars/room.svg';
-import AdminRoomAvatar from '../../../assets/images/avatars/admin-room.svg';
-import Android from '../../../assets/images/android.svg';
-import AnnounceRoomAvatar from '../../../assets/images/avatars/announce-room.svg';
-import Apple from '../../../assets/images/apple.svg';
-import AppleLogo from '../../../assets/images/signIn/apple-logo.svg';
-import ArrowRight from '../../../assets/images/arrow-right.svg';
-import ArrowRightLong from '../../../assets/images/arrow-right-long.svg';
-import ArrowsUpDown from '../../../assets/images/arrows-updown.svg';
-import BackArrow from '../../../assets/images/back-left.svg';
-import Bank from '../../../assets/images/bank.svg';
-import Bill from '../../../assets/images/bill.svg';
-import Bolt from '../../../assets/images/bolt.svg';
-import Briefcase from '../../../assets/images/briefcase.svg';
-import Bug from '../../../assets/images/bug.svg';
-import Building from '../../../assets/images/building.svg';
-import Calendar from '../../../assets/images/calendar.svg';
-import Camera from '../../../assets/images/camera.svg';
-import Car from '../../../assets/images/car.svg';
-import Cash from '../../../assets/images/cash.svg';
-import ChatBubble from '../../../assets/images/chatbubble.svg';
-import ChatBubbles from '../../../assets/images/chatbubbles.svg';
-import Checkmark from '../../../assets/images/checkmark.svg';
-import Chair from '../../../assets/images/chair.svg';
-import Close from '../../../assets/images/close.svg';
-import ClosedSign from '../../../assets/images/closed-sign.svg';
-import Collapse from '../../../assets/images/collapse.svg';
-import Concierge from '../../../assets/images/concierge.svg';
-import ConciergeAvatar from '../../../assets/images/avatars/concierge-avatar.svg';
-import Connect from '../../../assets/images/connect.svg';
-import Copy from '../../../assets/images/copy.svg';
-import CreditCard from '../../../assets/images/creditcard.svg';
-import Document from '../../../assets/images/document.svg';
-import DeletedRoomAvatar from '../../../assets/images/avatars/deleted-room.svg';
-import DomainRoomAvatar from '../../../assets/images/avatars/domain-room.svg';
-import DotIndicator from '../../../assets/images/dot-indicator.svg';
-import DotIndicatorUnfilled from '../../../assets/images/dot-indicator-unfilled.svg';
-import DownArrow from '../../../assets/images/down.svg';
-import Download from '../../../assets/images/download.svg';
-import DragHandles from '../../../assets/images/drag-handles.svg';
-import Emoji from '../../../assets/images/emoji.svg';
-import EmptyStateRoutePending from '../../../assets/images/emptystate__routepending.svg';
-import Exclamation from '../../../assets/images/exclamation.svg';
-import Exit from '../../../assets/images/exit.svg';
-import ExpensifyCard from '../../../assets/images/expensifycard.svg';
-import ExpensifyWordmark from '../../../assets/images/expensify-wordmark.svg';
-import Expand from '../../../assets/images/expand.svg';
-import Eye from '../../../assets/images/eye.svg';
-import EyeDisabled from '../../../assets/images/eye-disabled.svg';
-import Flag from '../../../assets/images/flag.svg';
-import FlagLevelOne from '../../../assets/images/flag_level_01.svg';
-import FlagLevelTwo from '../../../assets/images/flag_level_02.svg';
-import FlagLevelThree from '../../../assets/images/flag_level_03.svg';
-import Gallery from '../../../assets/images/gallery.svg';
-import Gear from '../../../assets/images/gear.svg';
-import Globe from '../../../assets/images/globe.svg';
-import GoogleLogo from '../../../assets/images/signIn/google-logo.svg';
-import Hashtag from '../../../assets/images/hashtag.svg';
-import Heart from '../../../assets/images/heart.svg';
-import History from '../../../assets/images/history.svg';
-import Hourglass from '../../../assets/images/hourglass.svg';
-import ImageCropCircleMask from '../../../assets/images/image-crop-circle-mask.svg';
-import ImageCropSquareMask from '../../../assets/images/image-crop-square-mask.svg';
-import Info from '../../../assets/images/info.svg';
-import Invoice from '../../../assets/images/invoice.svg';
-import Key from '../../../assets/images/key.svg';
-import Keyboard from '../../../assets/images/keyboard.svg';
-import Link from '../../../assets/images/link.svg';
-import LinkCopy from '../../../assets/images/link-copy.svg';
-import Location from '../../../assets/images/location.svg';
-import Lock from '../../../assets/images/lock.svg';
+import AddReaction from '@assets/images/add-reaction.svg';
+import Android from '@assets/images/android.svg';
+import Apple from '@assets/images/apple.svg';
+import ArrowRightLong from '@assets/images/arrow-right-long.svg';
+import ArrowRight from '@assets/images/arrow-right.svg';
+import UpArrow from '@assets/images/arrow-up.svg';
+import ArrowsUpDown from '@assets/images/arrows-updown.svg';
+import AdminRoomAvatar from '@assets/images/avatars/admin-room.svg';
+import AnnounceRoomAvatar from '@assets/images/avatars/announce-room.svg';
+import ConciergeAvatar from '@assets/images/avatars/concierge-avatar.svg';
+import DeletedRoomAvatar from '@assets/images/avatars/deleted-room.svg';
+import DomainRoomAvatar from '@assets/images/avatars/domain-room.svg';
+import FallbackAvatar from '@assets/images/avatars/fallback-avatar.svg';
+import FallbackWorkspaceAvatar from '@assets/images/avatars/fallback-workspace-avatar.svg';
+import ActiveRoomAvatar from '@assets/images/avatars/room.svg';
+import BackArrow from '@assets/images/back-left.svg';
+import Bank from '@assets/images/bank.svg';
+import Bell from '@assets/images/bell.svg';
+import BellSlash from '@assets/images/bellSlash.svg';
+import Bill from '@assets/images/bill.svg';
+import Bolt from '@assets/images/bolt.svg';
+import Briefcase from '@assets/images/briefcase.svg';
+import Bug from '@assets/images/bug.svg';
+import Building from '@assets/images/building.svg';
+import Calendar from '@assets/images/calendar.svg';
+import Camera from '@assets/images/camera.svg';
+import Car from '@assets/images/car.svg';
+import Cash from '@assets/images/cash.svg';
+import Chair from '@assets/images/chair.svg';
+import ChatBubble from '@assets/images/chatbubble.svg';
+import ChatBubbles from '@assets/images/chatbubbles.svg';
+import Checkmark from '@assets/images/checkmark.svg';
+import Close from '@assets/images/close.svg';
+import ClosedSign from '@assets/images/closed-sign.svg';
+import Collapse from '@assets/images/collapse.svg';
+import Concierge from '@assets/images/concierge.svg';
+import Connect from '@assets/images/connect.svg';
+import Copy from '@assets/images/copy.svg';
+import CreditCard from '@assets/images/creditcard.svg';
+import Document from '@assets/images/document.svg';
+import DotIndicatorUnfilled from '@assets/images/dot-indicator-unfilled.svg';
+import DotIndicator from '@assets/images/dot-indicator.svg';
+import DownArrow from '@assets/images/down.svg';
+import Download from '@assets/images/download.svg';
+import DragAndDrop from '@assets/images/drag-and-drop.svg';
+import DragHandles from '@assets/images/drag-handles.svg';
+import Emoji from '@assets/images/emoji.svg';
+import EmptyStateRoutePending from '@assets/images/emptystate__routepending.svg';
+import EReceiptIcon from '@assets/images/eReceiptIcon.svg';
+import Exclamation from '@assets/images/exclamation.svg';
+import Exit from '@assets/images/exit.svg';
+import Expand from '@assets/images/expand.svg';
+import ExpensifyFooterLogoVertical from '@assets/images/expensify-footer-logo-vertical.svg';
+import ExpensifyFooterLogo from '@assets/images/expensify-footer-logo.svg';
+import ExpensifyWordmark from '@assets/images/expensify-wordmark.svg';
+import ExpensifyCard from '@assets/images/expensifycard.svg';
+import EyeDisabled from '@assets/images/eye-disabled.svg';
+import Eye from '@assets/images/eye.svg';
+import Flag from '@assets/images/flag.svg';
+import FlagLevelOne from '@assets/images/flag_level_01.svg';
+import FlagLevelTwo from '@assets/images/flag_level_02.svg';
+import FlagLevelThree from '@assets/images/flag_level_03.svg';
+import Gallery from '@assets/images/gallery.svg';
+import Gear from '@assets/images/gear.svg';
+import Globe from '@assets/images/globe.svg';
+import Hashtag from '@assets/images/hashtag.svg';
+import Heart from '@assets/images/heart.svg';
+import History from '@assets/images/history.svg';
+import Hourglass from '@assets/images/hourglass.svg';
+import ImageCropCircleMask from '@assets/images/image-crop-circle-mask.svg';
+import ImageCropSquareMask from '@assets/images/image-crop-square-mask.svg';
+import Info from '@assets/images/info.svg';
+import Invoice from '@assets/images/invoice.svg';
+import Key from '@assets/images/key.svg';
+import Keyboard from '@assets/images/keyboard.svg';
+import LinkCopy from '@assets/images/link-copy.svg';
+import Link from '@assets/images/link.svg';
+import Location from '@assets/images/location.svg';
+import Lock from '@assets/images/lock.svg';
+import Luggage from '@assets/images/luggage.svg';
+import MagnifyingGlass from '@assets/images/magnifying-glass.svg';
+import Mail from '@assets/images/mail.svg';
+import Megaphone from '@assets/images/megaphone.svg';
+import Menu from '@assets/images/menu.svg';
+import MoneyBag from '@assets/images/money-bag.svg';
+import MoneyCircle from '@assets/images/money-circle.svg';
+import Monitor from '@assets/images/monitor.svg';
+import NewWindow from '@assets/images/new-window.svg';
+import NewWorkspace from '@assets/images/new-workspace.svg';
+import OfflineCloud from '@assets/images/offline-cloud.svg';
+import Offline from '@assets/images/offline.svg';
+import Paperclip from '@assets/images/paperclip.svg';
+import Paycheck from '@assets/images/paycheck.svg';
+import Pencil from '@assets/images/pencil.svg';
+import Phone from '@assets/images/phone.svg';
+import Pin from '@assets/images/pin.svg';
+import Plus from '@assets/images/plus.svg';
+import Printer from '@assets/images/printer.svg';
+import Profile from '@assets/images/profile.svg';
+import QrCode from '@assets/images/qrcode.svg';
+import QuestionMark from '@assets/images/question-mark-circle.svg';
+import ReceiptSearch from '@assets/images/receipt-search.svg';
+import Receipt from '@assets/images/receipt.svg';
+import Rotate from '@assets/images/rotate-image.svg';
+import RotateLeft from '@assets/images/rotate-left.svg';
+import Send from '@assets/images/send.svg';
+import Shield from '@assets/images/shield.svg';
+import AppleLogo from '@assets/images/signIn/apple-logo.svg';
+import GoogleLogo from '@assets/images/signIn/google-logo.svg';
+import Facebook from '@assets/images/social-facebook.svg';
+import Instagram from '@assets/images/social-instagram.svg';
+import Linkedin from '@assets/images/social-linkedin.svg';
+import Podcast from '@assets/images/social-podcast.svg';
+import Twitter from '@assets/images/social-twitter.svg';
+import Youtube from '@assets/images/social-youtube.svg';
+import Sync from '@assets/images/sync.svg';
+import Task from '@assets/images/task.svg';
+import ThreeDots from '@assets/images/three-dots.svg';
+import Transfer from '@assets/images/transfer.svg';
+import Trashcan from '@assets/images/trashcan.svg';
+import Unlock from '@assets/images/unlock.svg';
+import UploadAlt from '@assets/images/upload-alt.svg';
+import Upload from '@assets/images/upload.svg';
+import User from '@assets/images/user.svg';
+import Users from '@assets/images/users.svg';
+import Wallet from '@assets/images/wallet.svg';
+import Workspace from '@assets/images/workspace-default-avatar.svg';
+import Zoom from '@assets/images/zoom.svg';
import LoungeAccess from './svgs/LoungeAccessIcon';
-import Luggage from '../../../assets/images/luggage.svg';
-import MagnifyingGlass from '../../../assets/images/magnifying-glass.svg';
-import Mail from '../../../assets/images/mail.svg';
-import Megaphone from '../../../assets/images/megaphone.svg';
-import Menu from '../../../assets/images/menu.svg';
-import MoneyBag from '../../../assets/images/money-bag.svg';
-import MoneyCircle from '../../../assets/images/money-circle.svg';
-import Monitor from '../../../assets/images/monitor.svg';
-import NewWindow from '../../../assets/images/new-window.svg';
-import NewWorkspace from '../../../assets/images/new-workspace.svg';
-import Offline from '../../../assets/images/offline.svg';
-import OfflineCloud from '../../../assets/images/offline-cloud.svg';
-import Paperclip from '../../../assets/images/paperclip.svg';
-import Paycheck from '../../../assets/images/paycheck.svg';
-import Pencil from '../../../assets/images/pencil.svg';
-import Phone from '../../../assets/images/phone.svg';
-import Pin from '../../../assets/images/pin.svg';
-import Plus from '../../../assets/images/plus.svg';
-import Printer from '../../../assets/images/printer.svg';
-import Profile from '../../../assets/images/profile.svg';
-import QrCode from '../../../assets/images/qrcode.svg';
-import QuestionMark from '../../../assets/images/question-mark-circle.svg';
-import Receipt from '../../../assets/images/receipt.svg';
-import ReceiptSearch from '../../../assets/images/receipt-search.svg';
-import Rotate from '../../../assets/images/rotate-image.svg';
-import RotateLeft from '../../../assets/images/rotate-left.svg';
-import Send from '../../../assets/images/send.svg';
-import Shield from '../../../assets/images/shield.svg';
-import Sync from '../../../assets/images/sync.svg';
-import ThreeDots from '../../../assets/images/three-dots.svg';
-import Transfer from '../../../assets/images/transfer.svg';
-import Trashcan from '../../../assets/images/trashcan.svg';
-import Unlock from '../../../assets/images/unlock.svg';
-import UpArrow from '../../../assets/images/arrow-up.svg';
-import Upload from '../../../assets/images/upload.svg';
-import UploadAlt from '../../../assets/images/upload-alt.svg';
-import User from '../../../assets/images/user.svg';
-import Users from '../../../assets/images/users.svg';
-import Wallet from '../../../assets/images/wallet.svg';
-import Workspace from '../../../assets/images/workspace-default-avatar.svg';
-import Zoom from '../../../assets/images/zoom.svg';
-import FallbackAvatar from '../../../assets/images/avatars/fallback-avatar.svg';
-import FallbackWorkspaceAvatar from '../../../assets/images/avatars/fallback-workspace-avatar.svg';
-import DragAndDrop from '../../../assets/images/drag-and-drop.svg';
-import ExpensifyFooterLogo from '../../../assets/images/expensify-footer-logo.svg';
-import ExpensifyFooterLogoVertical from '../../../assets/images/expensify-footer-logo-vertical.svg';
-import Twitter from '../../../assets/images/social-twitter.svg';
-import Youtube from '../../../assets/images/social-youtube.svg';
-import Facebook from '../../../assets/images/social-facebook.svg';
-import Podcast from '../../../assets/images/social-podcast.svg';
-import Linkedin from '../../../assets/images/social-linkedin.svg';
-import Instagram from '../../../assets/images/social-instagram.svg';
-import AddReaction from '../../../assets/images/add-reaction.svg';
-import Task from '../../../assets/images/task.svg';
-import EReceiptIcon from '../../../assets/images/eReceiptIcon.svg';
export {
ActiveRoomAvatar,
@@ -140,6 +142,8 @@ export {
BackArrow,
Bank,
Bill,
+ Bell,
+ BellSlash,
Bolt,
Briefcase,
Bug,
diff --git a/src/components/Icon/Illustrations.js b/src/components/Icon/Illustrations.js
index c9a86cf8f10c..728e5b830fa6 100644
--- a/src/components/Icon/Illustrations.js
+++ b/src/components/Icon/Illustrations.js
@@ -1,52 +1,52 @@
-import Abracadabra from '../../../assets/images/product-illustrations/abracadabra.svg';
-import BankArrowPink from '../../../assets/images/product-illustrations/bank-arrow--pink.svg';
-import BankMouseGreen from '../../../assets/images/product-illustrations/bank-mouse--green.svg';
-import BankUserGreen from '../../../assets/images/product-illustrations/bank-user--green.svg';
-import ChatBubbles from '../../../assets/images/simple-illustrations/simple-illustration__chatbubbles.svg';
-import CoffeeMug from '../../../assets/images/simple-illustrations/simple-illustration__coffeemug.svg';
-import ConciergeBlue from '../../../assets/images/product-illustrations/concierge--blue.svg';
-import ConciergeExclamation from '../../../assets/images/product-illustrations/concierge--exclamation.svg';
-import CreditCardsBlue from '../../../assets/images/product-illustrations/credit-cards--blue.svg';
-import EmailAddress from '../../../assets/images/simple-illustrations/simple-illustration__email-address.svg';
-import InvoiceOrange from '../../../assets/images/product-illustrations/invoice--orange.svg';
-import JewelBoxBlue from '../../../assets/images/product-illustrations/jewel-box--blue.svg';
-import JewelBoxGreen from '../../../assets/images/product-illustrations/jewel-box--green.svg';
-import JewelBoxPink from '../../../assets/images/product-illustrations/jewel-box--pink.svg';
-import JewelBoxYellow from '../../../assets/images/product-illustrations/jewel-box--yellow.svg';
-import MagicCode from '../../../assets/images/product-illustrations/magic-code.svg';
-import MoneyEnvelopeBlue from '../../../assets/images/product-illustrations/money-envelope--blue.svg';
-import MoneyMousePink from '../../../assets/images/product-illustrations/money-mouse--pink.svg';
-import ReceiptsSearchYellow from '../../../assets/images/product-illustrations/receipts-search--yellow.svg';
-import ReceiptYellow from '../../../assets/images/product-illustrations/receipt--yellow.svg';
-import RocketBlue from '../../../assets/images/product-illustrations/rocket--blue.svg';
-import RocketOrange from '../../../assets/images/product-illustrations/rocket--orange.svg';
-import SafeBlue from '../../../assets/images/product-illustrations/safe.svg';
-import SanFrancisco from '../../../assets/images/simple-illustrations/simple-illustration__sanfrancisco.svg';
-import TadaYellow from '../../../assets/images/product-illustrations/tada--yellow.svg';
-import TadaBlue from '../../../assets/images/product-illustrations/tada--blue.svg';
-import ToddBehindCloud from '../../../assets/images/product-illustrations/todd-behind-cloud.svg';
-import GpsTrackOrange from '../../../assets/images/product-illustrations/gps-track--orange.svg';
-import ShieldYellow from '../../../assets/images/simple-illustrations/simple-illustration__shield.svg';
-import MoneyReceipts from '../../../assets/images/simple-illustrations/simple-illustration__money-receipts.svg';
-import PinkBill from '../../../assets/images/simple-illustrations/simple-illustration__bill.svg';
-import CreditCardsNew from '../../../assets/images/simple-illustrations/simple-illustration__credit-cards.svg';
-import InvoiceBlue from '../../../assets/images/simple-illustrations/simple-illustration__invoice.svg';
-import LockOpen from '../../../assets/images/simple-illustrations/simple-illustration__lockopen.svg';
-import Lounge from '../../../assets/images/product-illustrations/lounge.svg';
-import Luggage from '../../../assets/images/simple-illustrations/simple-illustration__luggage.svg';
-import MoneyIntoWallet from '../../../assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg';
-import MoneyWings from '../../../assets/images/simple-illustrations/simple-illustration__moneywings.svg';
-import OpenSafe from '../../../assets/images/simple-illustrations/simple-illustration__opensafe.svg';
-import TrackShoe from '../../../assets/images/simple-illustrations/simple-illustration__track-shoe.svg';
-import BankArrow from '../../../assets/images/simple-illustrations/simple-illustration__bank-arrow.svg';
-import ConciergeBubble from '../../../assets/images/simple-illustrations/simple-illustration__concierge-bubble.svg';
-import ConciergeNew from '../../../assets/images/simple-illustrations/simple-illustration__concierge.svg';
-import MoneyBadge from '../../../assets/images/simple-illustrations/simple-illustration__moneybadge.svg';
-import TreasureChest from '../../../assets/images/simple-illustrations/simple-illustration__treasurechest.svg';
-import ThumbsUpStars from '../../../assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg';
-import Hands from '../../../assets/images/product-illustrations/home-illustration-hands.svg';
-import HandEarth from '../../../assets/images/simple-illustrations/simple-illustration__handearth.svg';
-import SmartScan from '../../../assets/images/product-illustrations/simple-illustration__smartscan.svg';
+import Abracadabra from '@assets/images/product-illustrations/abracadabra.svg';
+import BankArrowPink from '@assets/images/product-illustrations/bank-arrow--pink.svg';
+import BankMouseGreen from '@assets/images/product-illustrations/bank-mouse--green.svg';
+import BankUserGreen from '@assets/images/product-illustrations/bank-user--green.svg';
+import ConciergeBlue from '@assets/images/product-illustrations/concierge--blue.svg';
+import ConciergeExclamation from '@assets/images/product-illustrations/concierge--exclamation.svg';
+import CreditCardsBlue from '@assets/images/product-illustrations/credit-cards--blue.svg';
+import GpsTrackOrange from '@assets/images/product-illustrations/gps-track--orange.svg';
+import Hands from '@assets/images/product-illustrations/home-illustration-hands.svg';
+import InvoiceOrange from '@assets/images/product-illustrations/invoice--orange.svg';
+import JewelBoxBlue from '@assets/images/product-illustrations/jewel-box--blue.svg';
+import JewelBoxGreen from '@assets/images/product-illustrations/jewel-box--green.svg';
+import JewelBoxPink from '@assets/images/product-illustrations/jewel-box--pink.svg';
+import JewelBoxYellow from '@assets/images/product-illustrations/jewel-box--yellow.svg';
+import Lounge from '@assets/images/product-illustrations/lounge.svg';
+import MagicCode from '@assets/images/product-illustrations/magic-code.svg';
+import MoneyEnvelopeBlue from '@assets/images/product-illustrations/money-envelope--blue.svg';
+import MoneyMousePink from '@assets/images/product-illustrations/money-mouse--pink.svg';
+import ReceiptYellow from '@assets/images/product-illustrations/receipt--yellow.svg';
+import ReceiptsSearchYellow from '@assets/images/product-illustrations/receipts-search--yellow.svg';
+import RocketBlue from '@assets/images/product-illustrations/rocket--blue.svg';
+import RocketOrange from '@assets/images/product-illustrations/rocket--orange.svg';
+import SafeBlue from '@assets/images/product-illustrations/safe.svg';
+import SmartScan from '@assets/images/product-illustrations/simple-illustration__smartscan.svg';
+import TadaBlue from '@assets/images/product-illustrations/tada--blue.svg';
+import TadaYellow from '@assets/images/product-illustrations/tada--yellow.svg';
+import ToddBehindCloud from '@assets/images/product-illustrations/todd-behind-cloud.svg';
+import BankArrow from '@assets/images/simple-illustrations/simple-illustration__bank-arrow.svg';
+import PinkBill from '@assets/images/simple-illustrations/simple-illustration__bill.svg';
+import ChatBubbles from '@assets/images/simple-illustrations/simple-illustration__chatbubbles.svg';
+import CoffeeMug from '@assets/images/simple-illustrations/simple-illustration__coffeemug.svg';
+import ConciergeBubble from '@assets/images/simple-illustrations/simple-illustration__concierge-bubble.svg';
+import ConciergeNew from '@assets/images/simple-illustrations/simple-illustration__concierge.svg';
+import CreditCardsNew from '@assets/images/simple-illustrations/simple-illustration__credit-cards.svg';
+import EmailAddress from '@assets/images/simple-illustrations/simple-illustration__email-address.svg';
+import HandEarth from '@assets/images/simple-illustrations/simple-illustration__handearth.svg';
+import InvoiceBlue from '@assets/images/simple-illustrations/simple-illustration__invoice.svg';
+import LockOpen from '@assets/images/simple-illustrations/simple-illustration__lockopen.svg';
+import Luggage from '@assets/images/simple-illustrations/simple-illustration__luggage.svg';
+import MoneyReceipts from '@assets/images/simple-illustrations/simple-illustration__money-receipts.svg';
+import MoneyBadge from '@assets/images/simple-illustrations/simple-illustration__moneybadge.svg';
+import MoneyIntoWallet from '@assets/images/simple-illustrations/simple-illustration__moneyintowallet.svg';
+import MoneyWings from '@assets/images/simple-illustrations/simple-illustration__moneywings.svg';
+import OpenSafe from '@assets/images/simple-illustrations/simple-illustration__opensafe.svg';
+import SanFrancisco from '@assets/images/simple-illustrations/simple-illustration__sanfrancisco.svg';
+import ShieldYellow from '@assets/images/simple-illustrations/simple-illustration__shield.svg';
+import ThumbsUpStars from '@assets/images/simple-illustrations/simple-illustration__thumbsupstars.svg';
+import TrackShoe from '@assets/images/simple-illustrations/simple-illustration__track-shoe.svg';
+import TreasureChest from '@assets/images/simple-illustrations/simple-illustration__treasurechest.svg';
export {
Abracadabra,
diff --git a/src/components/Icon/MCCIcons.js b/src/components/Icon/MCCIcons.js
index a704f7d46bc6..922fb274f23d 100644
--- a/src/components/Icon/MCCIcons.js
+++ b/src/components/Icon/MCCIcons.js
@@ -1,15 +1,15 @@
-import Airlines from '../../../assets/images/MCCGroupIcons/MCC-Airlines.svg';
-import Commuter from '../../../assets/images/MCCGroupIcons/MCC-Commuter.svg';
-import Gas from '../../../assets/images/MCCGroupIcons/MCC-Gas.svg';
-import Goods from '../../../assets/images/MCCGroupIcons/MCC-Goods.svg';
-import Groceries from '../../../assets/images/MCCGroupIcons/MCC-Groceries.svg';
-import Hotel from '../../../assets/images/MCCGroupIcons/MCC-Hotel.svg';
-import Mail from '../../../assets/images/MCCGroupIcons/MCC-Mail.svg';
-import Meals from '../../../assets/images/MCCGroupIcons/MCC-Meals.svg';
-import Rental from '../../../assets/images/MCCGroupIcons/MCC-RentalCar.svg';
-import Services from '../../../assets/images/MCCGroupIcons/MCC-Services.svg';
-import Taxi from '../../../assets/images/MCCGroupIcons/MCC-Taxi.svg';
-import Miscellaneous from '../../../assets/images/MCCGroupIcons/MCC-Misc.svg';
-import Utilities from '../../../assets/images/MCCGroupIcons/MCC-Utilities.svg';
+import Airlines from '@assets/images/MCCGroupIcons/MCC-Airlines.svg';
+import Commuter from '@assets/images/MCCGroupIcons/MCC-Commuter.svg';
+import Gas from '@assets/images/MCCGroupIcons/MCC-Gas.svg';
+import Goods from '@assets/images/MCCGroupIcons/MCC-Goods.svg';
+import Groceries from '@assets/images/MCCGroupIcons/MCC-Groceries.svg';
+import Hotel from '@assets/images/MCCGroupIcons/MCC-Hotel.svg';
+import Mail from '@assets/images/MCCGroupIcons/MCC-Mail.svg';
+import Meals from '@assets/images/MCCGroupIcons/MCC-Meals.svg';
+import Miscellaneous from '@assets/images/MCCGroupIcons/MCC-Misc.svg';
+import Rental from '@assets/images/MCCGroupIcons/MCC-RentalCar.svg';
+import Services from '@assets/images/MCCGroupIcons/MCC-Services.svg';
+import Taxi from '@assets/images/MCCGroupIcons/MCC-Taxi.svg';
+import Utilities from '@assets/images/MCCGroupIcons/MCC-Utilities.svg';
export {Airlines, Commuter, Gas, Goods, Groceries, Hotel, Mail, Meals, Rental, Services, Taxi, Miscellaneous, Utilities};
diff --git a/src/components/Icon/WorkspaceDefaultAvatars.js b/src/components/Icon/WorkspaceDefaultAvatars.js
index 0f5490b981bd..53d2ca088118 100644
--- a/src/components/Icon/WorkspaceDefaultAvatars.js
+++ b/src/components/Icon/WorkspaceDefaultAvatars.js
@@ -1,40 +1,40 @@
-import Workspace0 from '../../../assets/images/avatars/workspace/default-avatar_0.svg';
-import Workspace1 from '../../../assets/images/avatars/workspace/default-avatar_1.svg';
-import Workspace2 from '../../../assets/images/avatars/workspace/default-avatar_2.svg';
-import Workspace3 from '../../../assets/images/avatars/workspace/default-avatar_3.svg';
-import Workspace4 from '../../../assets/images/avatars/workspace/default-avatar_4.svg';
-import Workspace5 from '../../../assets/images/avatars/workspace/default-avatar_5.svg';
-import Workspace6 from '../../../assets/images/avatars/workspace/default-avatar_6.svg';
-import Workspace7 from '../../../assets/images/avatars/workspace/default-avatar_7.svg';
-import Workspace8 from '../../../assets/images/avatars/workspace/default-avatar_8.svg';
-import Workspace9 from '../../../assets/images/avatars/workspace/default-avatar_9.svg';
-import WorkspaceA from '../../../assets/images/avatars/workspace/default-avatar_a.svg';
-import WorkspaceB from '../../../assets/images/avatars/workspace/default-avatar_b.svg';
-import WorkspaceC from '../../../assets/images/avatars/workspace/default-avatar_c.svg';
-import WorkspaceD from '../../../assets/images/avatars/workspace/default-avatar_d.svg';
-import WorkspaceE from '../../../assets/images/avatars/workspace/default-avatar_e.svg';
-import WorkspaceF from '../../../assets/images/avatars/workspace/default-avatar_f.svg';
-import WorkspaceG from '../../../assets/images/avatars/workspace/default-avatar_g.svg';
-import WorkspaceH from '../../../assets/images/avatars/workspace/default-avatar_h.svg';
-import WorkspaceI from '../../../assets/images/avatars/workspace/default-avatar_i.svg';
-import WorkspaceJ from '../../../assets/images/avatars/workspace/default-avatar_j.svg';
-import WorkspaceK from '../../../assets/images/avatars/workspace/default-avatar_k.svg';
-import WorkspaceL from '../../../assets/images/avatars/workspace/default-avatar_l.svg';
-import WorkspaceM from '../../../assets/images/avatars/workspace/default-avatar_m.svg';
-import WorkspaceN from '../../../assets/images/avatars/workspace/default-avatar_n.svg';
-import WorkspaceO from '../../../assets/images/avatars/workspace/default-avatar_o.svg';
-import WorkspaceP from '../../../assets/images/avatars/workspace/default-avatar_p.svg';
-import WorkspaceQ from '../../../assets/images/avatars/workspace/default-avatar_q.svg';
-import WorkspaceR from '../../../assets/images/avatars/workspace/default-avatar_r.svg';
-import WorkspaceS from '../../../assets/images/avatars/workspace/default-avatar_s.svg';
-import WorkspaceT from '../../../assets/images/avatars/workspace/default-avatar_t.svg';
-import WorkspaceU from '../../../assets/images/avatars/workspace/default-avatar_u.svg';
-import WorkspaceV from '../../../assets/images/avatars/workspace/default-avatar_v.svg';
-import WorkspaceW from '../../../assets/images/avatars/workspace/default-avatar_w.svg';
-import WorkspaceX from '../../../assets/images/avatars/workspace/default-avatar_x.svg';
-import WorkspaceY from '../../../assets/images/avatars/workspace/default-avatar_y.svg';
-import WorkspaceZ from '../../../assets/images/avatars/workspace/default-avatar_z.svg';
-import WorkspaceBuilding from '../../../assets/images/avatars/workspace/default-avatar_building.svg';
+import Workspace0 from '@assets/images/avatars/workspace/default-avatar_0.svg';
+import Workspace1 from '@assets/images/avatars/workspace/default-avatar_1.svg';
+import Workspace2 from '@assets/images/avatars/workspace/default-avatar_2.svg';
+import Workspace3 from '@assets/images/avatars/workspace/default-avatar_3.svg';
+import Workspace4 from '@assets/images/avatars/workspace/default-avatar_4.svg';
+import Workspace5 from '@assets/images/avatars/workspace/default-avatar_5.svg';
+import Workspace6 from '@assets/images/avatars/workspace/default-avatar_6.svg';
+import Workspace7 from '@assets/images/avatars/workspace/default-avatar_7.svg';
+import Workspace8 from '@assets/images/avatars/workspace/default-avatar_8.svg';
+import Workspace9 from '@assets/images/avatars/workspace/default-avatar_9.svg';
+import WorkspaceA from '@assets/images/avatars/workspace/default-avatar_a.svg';
+import WorkspaceB from '@assets/images/avatars/workspace/default-avatar_b.svg';
+import WorkspaceBuilding from '@assets/images/avatars/workspace/default-avatar_building.svg';
+import WorkspaceC from '@assets/images/avatars/workspace/default-avatar_c.svg';
+import WorkspaceD from '@assets/images/avatars/workspace/default-avatar_d.svg';
+import WorkspaceE from '@assets/images/avatars/workspace/default-avatar_e.svg';
+import WorkspaceF from '@assets/images/avatars/workspace/default-avatar_f.svg';
+import WorkspaceG from '@assets/images/avatars/workspace/default-avatar_g.svg';
+import WorkspaceH from '@assets/images/avatars/workspace/default-avatar_h.svg';
+import WorkspaceI from '@assets/images/avatars/workspace/default-avatar_i.svg';
+import WorkspaceJ from '@assets/images/avatars/workspace/default-avatar_j.svg';
+import WorkspaceK from '@assets/images/avatars/workspace/default-avatar_k.svg';
+import WorkspaceL from '@assets/images/avatars/workspace/default-avatar_l.svg';
+import WorkspaceM from '@assets/images/avatars/workspace/default-avatar_m.svg';
+import WorkspaceN from '@assets/images/avatars/workspace/default-avatar_n.svg';
+import WorkspaceO from '@assets/images/avatars/workspace/default-avatar_o.svg';
+import WorkspaceP from '@assets/images/avatars/workspace/default-avatar_p.svg';
+import WorkspaceQ from '@assets/images/avatars/workspace/default-avatar_q.svg';
+import WorkspaceR from '@assets/images/avatars/workspace/default-avatar_r.svg';
+import WorkspaceS from '@assets/images/avatars/workspace/default-avatar_s.svg';
+import WorkspaceT from '@assets/images/avatars/workspace/default-avatar_t.svg';
+import WorkspaceU from '@assets/images/avatars/workspace/default-avatar_u.svg';
+import WorkspaceV from '@assets/images/avatars/workspace/default-avatar_v.svg';
+import WorkspaceW from '@assets/images/avatars/workspace/default-avatar_w.svg';
+import WorkspaceX from '@assets/images/avatars/workspace/default-avatar_x.svg';
+import WorkspaceY from '@assets/images/avatars/workspace/default-avatar_y.svg';
+import WorkspaceZ from '@assets/images/avatars/workspace/default-avatar_z.svg';
export {
Workspace0,
diff --git a/src/components/Icon/index.js b/src/components/Icon/index.js
index 5cdd5c79704d..d4d95ca117d4 100644
--- a/src/components/Icon/index.js
+++ b/src/components/Icon/index.js
@@ -1,10 +1,10 @@
+import PropTypes from 'prop-types';
import React, {PureComponent} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import themeColors from '../../styles/themes/default';
-import variables from '../../styles/variables';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
import IconWrapperStyles from './IconWrapperStyles';
const propTypes = {
diff --git a/src/components/Icon/svgs/LoungeAccessIcon.js b/src/components/Icon/svgs/LoungeAccessIcon.js
index b00fbb312c85..9117fb24bb42 100644
--- a/src/components/Icon/svgs/LoungeAccessIcon.js
+++ b/src/components/Icon/svgs/LoungeAccessIcon.js
@@ -1,7 +1,7 @@
+import PropTypes from 'prop-types';
import * as React from 'react';
import Svg, {G, Path, Polygon} from 'react-native-svg';
-import PropTypes from 'prop-types';
-import themeColors from '../../../styles/themes/default';
+import themeColors from '@styles/themes/default';
const propTypes = {
/** The fill color for the icon. Can be hex, rgb, rgba, or valid react-native named color such as 'red' or 'blue'. */
diff --git a/src/components/IllustratedHeaderPageLayout.js b/src/components/IllustratedHeaderPageLayout.js
index c45f5e2452dd..54a3b0e7b07c 100644
--- a/src/components/IllustratedHeaderPageLayout.js
+++ b/src/components/IllustratedHeaderPageLayout.js
@@ -1,10 +1,10 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import Lottie from './Lottie';
-import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
+import React from 'react';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
import HeaderPageLayout from './HeaderPageLayout';
+import headerWithBackButtonPropTypes from './HeaderWithBackButton/headerWithBackButtonPropTypes';
+import Lottie from './Lottie';
const propTypes = {
...headerWithBackButtonPropTypes,
diff --git a/src/components/Image/imagePropTypes.js b/src/components/Image/imagePropTypes.js
index c02e48eef659..78bd48ba47ec 100644
--- a/src/components/Image/imagePropTypes.js
+++ b/src/components/Image/imagePropTypes.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
-import stylePropTypes from '../../styles/stylePropTypes';
-import sourcePropTypes from './sourcePropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
import RESIZE_MODES from './resizeModes';
+import sourcePropTypes from './sourcePropTypes';
const imagePropTypes = {
/** Styles for the Image */
diff --git a/src/components/Image/index.js b/src/components/Image/index.js
index 7434c16c6491..c2800511ff45 100644
--- a/src/components/Image/index.js
+++ b/src/components/Image/index.js
@@ -1,9 +1,9 @@
+import lodashGet from 'lodash/get';
import React, {useEffect, useMemo} from 'react';
import {Image as RNImage} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
import {defaultProps, imagePropTypes} from './imagePropTypes';
import RESIZE_MODES from './resizeModes';
diff --git a/src/components/Image/index.native.js b/src/components/Image/index.native.js
index 9d9ad600b1d4..52ac503081e6 100644
--- a/src/components/Image/index.native.js
+++ b/src/components/Image/index.native.js
@@ -1,9 +1,9 @@
+import lodashGet from 'lodash/get';
import React from 'react';
import RNFastImage from 'react-native-fast-image';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import {defaultProps, imagePropTypes} from './imagePropTypes';
import RESIZE_MODES from './resizeModes';
diff --git a/src/components/ImageView/index.js b/src/components/ImageView/index.js
index 1d90a5723016..09656d700917 100644
--- a/src/components/ImageView/index.js
+++ b/src/components/ImageView/index.js
@@ -1,13 +1,13 @@
-import React, {useState, useEffect, useRef, useCallback} from 'react';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
-import Image from '../Image';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import FullscreenLoadingIndicator from '../FullscreenLoadingIndicator';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import CONST from '../../CONST';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Image from '@components/Image';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether source url requires authentication */
diff --git a/src/components/ImageView/index.native.js b/src/components/ImageView/index.native.js
index b365f507a4fc..dd17e2d27a4e 100644
--- a/src/components/ImageView/index.native.js
+++ b/src/components/ImageView/index.native.js
@@ -1,13 +1,13 @@
-import React, {useState, useRef, useEffect} from 'react';
import PropTypes from 'prop-types';
-import {View, PanResponder} from 'react-native';
+import React, {useEffect, useRef, useState} from 'react';
+import {PanResponder, View} from 'react-native';
import ImageZoom from 'react-native-image-pan-zoom';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
-import FullscreenLoadingIndicator from '../FullscreenLoadingIndicator';
-import Image from '../Image';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Image from '@components/Image';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
/**
* On the native layer, we use a image library to handle zoom functionality
diff --git a/src/components/ImageWithSizeCalculation.js b/src/components/ImageWithSizeCalculation.js
index 6aa87d07f23e..5db78e0c1276 100644
--- a/src/components/ImageWithSizeCalculation.js
+++ b/src/components/ImageWithSizeCalculation.js
@@ -1,9 +1,9 @@
-import _ from 'underscore';
-import React, {useState, useRef, useEffect} from 'react';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
-import Log from '../libs/Log';
-import styles from '../styles/styles';
+import React, {useEffect, useRef, useState} from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import Log from '@libs/Log';
+import styles from '@styles/styles';
import FullscreenLoadingIndicator from './FullscreenLoadingIndicator';
import Image from './Image';
diff --git a/src/components/Indicator.js b/src/components/Indicator.js
index 24eb20ad5eee..046c3ca523e1 100644
--- a/src/components/Indicator.js
+++ b/src/components/Indicator.js
@@ -1,21 +1,21 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React from 'react';
import {StyleSheet, View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import styles from '../styles/styles';
-import ONYXKEYS from '../ONYXKEYS';
-import policyMemberPropType from '../pages/policyMemberPropType';
+import _ from 'underscore';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as UserUtils from '@libs/UserUtils';
+import userWalletPropTypes from '@pages/EnablePayments/userWalletPropTypes';
+import walletTermsPropTypes from '@pages/EnablePayments/walletTermsPropTypes';
+import policyMemberPropType from '@pages/policyMemberPropType';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import {policyPropTypes} from '@pages/workspace/withPolicy';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import ONYXKEYS from '@src/ONYXKEYS';
import bankAccountPropTypes from './bankAccountPropTypes';
import cardPropTypes from './cardPropTypes';
-import userWalletPropTypes from '../pages/EnablePayments/userWalletPropTypes';
-import {policyPropTypes} from '../pages/workspace/withPolicy';
-import walletTermsPropTypes from '../pages/EnablePayments/walletTermsPropTypes';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import * as PaymentMethods from '../libs/actions/PaymentMethods';
-import * as ReimbursementAccountProps from '../pages/ReimbursementAccount/reimbursementAccountPropTypes';
-import * as UserUtils from '../libs/UserUtils';
-import themeColors from '../styles/themes/default';
const propTypes = {
/* Onyx Props */
diff --git a/src/components/InlineCodeBlock/WrappedText.js b/src/components/InlineCodeBlock/WrappedText.js
index 14bab44f2126..e28f0f6b1f55 100644
--- a/src/components/InlineCodeBlock/WrappedText.js
+++ b/src/components/InlineCodeBlock/WrappedText.js
@@ -1,10 +1,10 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React, {Fragment} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import CONST from '../../CONST';
+import _ from 'underscore';
+import Text from '@components/Text';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
/**
* Breaks the text into matrix
diff --git a/src/components/InlineCodeBlock/index.js b/src/components/InlineCodeBlock/index.js
index 7610ba4fa583..84666931d9b2 100644
--- a/src/components/InlineCodeBlock/index.js
+++ b/src/components/InlineCodeBlock/index.js
@@ -1,7 +1,7 @@
-import React from 'react';
import _ from 'lodash';
+import React from 'react';
+import Text from '@components/Text';
import inlineCodeBlockPropTypes from './inlineCodeBlockPropTypes';
-import Text from '../Text';
function InlineCodeBlock(props) {
const TDefaultRenderer = props.TDefaultRenderer;
diff --git a/src/components/InlineCodeBlock/index.native.js b/src/components/InlineCodeBlock/index.native.js
index 2aa718832180..ff92ebbbcb9e 100644
--- a/src/components/InlineCodeBlock/index.native.js
+++ b/src/components/InlineCodeBlock/index.native.js
@@ -1,7 +1,7 @@
import React from 'react';
-import styles from '../../styles/styles';
-import WrappedText from './WrappedText';
+import styles from '@styles/styles';
import inlineCodeBlockPropTypes from './inlineCodeBlockPropTypes';
+import WrappedText from './WrappedText';
function InlineCodeBlock(props) {
const TDefaultRenderer = props.TDefaultRenderer;
diff --git a/src/components/InlineErrorText.js b/src/components/InlineErrorText.js
index ea701a3f6e8e..80438eea8b5f 100644
--- a/src/components/InlineErrorText.js
+++ b/src/components/InlineErrorText.js
@@ -1,7 +1,7 @@
-import _ from 'underscore';
-import React from 'react';
import PropTypes from 'prop-types';
-import styles from '../styles/styles';
+import React from 'react';
+import _ from 'underscore';
+import styles from '@styles/styles';
import Text from './Text';
const propTypes = {
diff --git a/src/components/InlineSystemMessage.js b/src/components/InlineSystemMessage.tsx
similarity index 53%
rename from src/components/InlineSystemMessage.js
rename to src/components/InlineSystemMessage.tsx
index a6866fb5a887..e9de0111cd23 100644
--- a/src/components/InlineSystemMessage.js
+++ b/src/components/InlineSystemMessage.tsx
@@ -1,37 +1,32 @@
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
-import theme from '../styles/themes/default';
-import Text from './Text';
-import * as Expensicons from './Icon/Expensicons';
+import styles from '@styles/styles';
+import theme from '@styles/themes/default';
import Icon from './Icon';
+import * as Expensicons from './Icon/Expensicons';
+import Text from './Text';
-const propTypes = {
+type InlineSystemMessageProps = {
/** Error to display */
- message: PropTypes.string,
+ message?: string;
};
-const defaultProps = {
- message: '',
-};
-
-function InlineSystemMessage(props) {
- if (props.message.length === 0) {
+function InlineSystemMessage({message = ''}: InlineSystemMessageProps) {
+ if (!message) {
return null;
}
+
return (
- {props.message}
+ {message}
);
}
-InlineSystemMessage.propTypes = propTypes;
-InlineSystemMessage.defaultProps = defaultProps;
InlineSystemMessage.displayName = 'InlineSystemMessage';
+
export default InlineSystemMessage;
diff --git a/src/components/InvertedFlatList/BaseInvertedFlatList.js b/src/components/InvertedFlatList/BaseInvertedFlatList.js
index f49214f5de70..802ae373d22a 100644
--- a/src/components/InvertedFlatList/BaseInvertedFlatList.js
+++ b/src/components/InvertedFlatList/BaseInvertedFlatList.js
@@ -1,9 +1,10 @@
+import PropTypes from 'prop-types';
import React, {forwardRef, useCallback, useRef} from 'react';
-import {View, FlatList as NativeFlatlist} from 'react-native';
+import {FlatList as NativeFlatlist, View} from 'react-native';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import * as CollectionUtils from '../../libs/CollectionUtils';
-import FlatList from '../FlatList';
+import FlatList from '@components/FlatList';
+import * as CollectionUtils from '@libs/CollectionUtils';
+import variables from '@styles/variables';
const propTypes = {
/** Same as FlatList can be any array of anything */
@@ -133,6 +134,10 @@ function BaseInvertedFlatList(props) {
// Web requires that items be measured or else crazy things happen when scrolling.
getItemLayout={shouldMeasureItems ? getItemLayout : undefined}
windowSize={15}
+ maintainVisibleContentPosition={{
+ minIndexForVisible: 0,
+ autoscrollToTopThreshold: variables.listItemHeightNormal,
+ }}
inverted
/>
);
@@ -142,10 +147,14 @@ BaseInvertedFlatList.propTypes = propTypes;
BaseInvertedFlatList.defaultProps = defaultProps;
BaseInvertedFlatList.displayName = 'BaseInvertedFlatList';
-export default forwardRef((props, ref) => (
+const BaseInvertedFlatListWithRef = forwardRef((props, ref) => (
));
+
+BaseInvertedFlatListWithRef.displayName = 'BaseInvertedFlatListWithRef';
+
+export default BaseInvertedFlatListWithRef;
diff --git a/src/components/InvertedFlatList/CellRendererComponent.js b/src/components/InvertedFlatList/CellRendererComponent.js
index 77397aeb4610..2b2d214000bf 100644
--- a/src/components/InvertedFlatList/CellRendererComponent.js
+++ b/src/components/InvertedFlatList/CellRendererComponent.js
@@ -1,6 +1,6 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
const propTypes = {
/** Position index of the list item in a list view */
diff --git a/src/components/InvertedFlatList/index.js b/src/components/InvertedFlatList/index.js
index 564db6296c9b..14b781759904 100644
--- a/src/components/InvertedFlatList/index.js
+++ b/src/components/InvertedFlatList/index.js
@@ -1,10 +1,10 @@
-import React, {forwardRef, useEffect, useRef} from 'react';
import PropTypes from 'prop-types';
+import React, {forwardRef, useEffect, useRef} from 'react';
import {DeviceEventEmitter, FlatList, StyleSheet} from 'react-native';
import _ from 'underscore';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import BaseInvertedFlatList from './BaseInvertedFlatList';
-import styles from '../../styles/styles';
-import CONST from '../../CONST';
const propTypes = {
/** Passed via forwardRef so we can access the FlatList ref */
@@ -131,10 +131,14 @@ InvertedFlatList.defaultProps = {
onScroll: () => {},
};
-export default forwardRef((props, ref) => (
+const InvertedFlatListWithRef = forwardRef((props, ref) => (
));
+
+InvertedFlatListWithRef.displayName = 'InvertedFlatListWithRef';
+
+export default InvertedFlatListWithRef;
diff --git a/src/components/InvertedFlatList/index.native.js b/src/components/InvertedFlatList/index.native.js
index ece86032d80b..8473b602d45f 100644
--- a/src/components/InvertedFlatList/index.native.js
+++ b/src/components/InvertedFlatList/index.native.js
@@ -2,7 +2,7 @@ import React, {forwardRef} from 'react';
import BaseInvertedFlatList from './BaseInvertedFlatList';
import CellRendererComponent from './CellRendererComponent';
-export default forwardRef((props, ref) => (
+const BaseInvertedFlatListWithRef = forwardRef((props, ref) => (
(
removeClippedSubviews={false}
/>
));
+
+BaseInvertedFlatListWithRef.displayName = 'BaseInvertedFlatListWithRef';
+
+export default BaseInvertedFlatListWithRef;
diff --git a/src/components/KYCWall/BaseKYCWall.js b/src/components/KYCWall/BaseKYCWall.js
index ccee8bc4e6a0..d55417a6190a 100644
--- a/src/components/KYCWall/BaseKYCWall.js
+++ b/src/components/KYCWall/BaseKYCWall.js
@@ -1,19 +1,19 @@
-import _ from 'underscore';
+import lodashGet from 'lodash/get';
import React from 'react';
-import {withOnyx} from 'react-native-onyx';
import {Dimensions} from 'react-native';
-import lodashGet from 'lodash/get';
-import CONST from '../../CONST';
-import Navigation from '../../libs/Navigation/Navigation';
-import AddPaymentMethodMenu from '../AddPaymentMethodMenu';
-import getClickedTargetLocation from '../../libs/getClickedTargetLocation';
-import * as PaymentUtils from '../../libs/PaymentUtils';
-import * as PaymentMethods from '../../libs/actions/PaymentMethods';
-import ONYXKEYS from '../../ONYXKEYS';
-import Log from '../../libs/Log';
-import {propTypes, defaultProps} from './kycWallPropTypes';
-import * as Wallet from '../../libs/actions/Wallet';
-import * as ReportUtils from '../../libs/ReportUtils';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import AddPaymentMethodMenu from '@components/AddPaymentMethodMenu';
+import getClickedTargetLocation from '@libs/getClickedTargetLocation';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PaymentUtils from '@libs/PaymentUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import * as Wallet from '@userActions/Wallet';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps, propTypes} from './kycWallPropTypes';
// This component allows us to block various actions by forcing the user to first add a default payment method and successfully make it through our Know Your Customer flow
// before continuing to take whatever action they originally intended to take. It requires a button as a child and a native event so we can get the coordinates and use it
diff --git a/src/components/KYCWall/index.js b/src/components/KYCWall/index.js
index 81e7a2d37481..49329c73d474 100644
--- a/src/components/KYCWall/index.js
+++ b/src/components/KYCWall/index.js
@@ -1,6 +1,6 @@
import React from 'react';
-import {propTypes, defaultProps} from './kycWallPropTypes';
import BaseKYCWall from './BaseKYCWall';
+import {defaultProps, propTypes} from './kycWallPropTypes';
function KYCWall(props) {
return (
diff --git a/src/components/KYCWall/kycWallPropTypes.js b/src/components/KYCWall/kycWallPropTypes.js
index b585535784dc..58db2c1c1940 100644
--- a/src/components/KYCWall/kycWallPropTypes.js
+++ b/src/components/KYCWall/kycWallPropTypes.js
@@ -1,12 +1,12 @@
-import _ from 'underscore';
import PropTypes from 'prop-types';
-import userWalletPropTypes from '../../pages/EnablePayments/userWalletPropTypes';
-import bankAccountPropTypes from '../bankAccountPropTypes';
-import cardPropTypes from '../cardPropTypes';
-import iouReportPropTypes from '../../pages/iouReportPropTypes';
-import reimbursementAccountPropTypes from '../../pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes';
-import walletTermsPropTypes from '../../pages/EnablePayments/walletTermsPropTypes';
-import CONST from '../../CONST';
+import _ from 'underscore';
+import bankAccountPropTypes from '@components/bankAccountPropTypes';
+import cardPropTypes from '@components/cardPropTypes';
+import userWalletPropTypes from '@pages/EnablePayments/userWalletPropTypes';
+import walletTermsPropTypes from '@pages/EnablePayments/walletTermsPropTypes';
+import iouReportPropTypes from '@pages/iouReportPropTypes';
+import reimbursementAccountPropTypes from '@pages/ReimbursementAccount/ReimbursementAccountDraftPropTypes';
+import CONST from '@src/CONST';
const propTypes = {
/** Route for the Add Bank Account screen for a given navigation stack */
diff --git a/src/components/KeyboardDismissingFlatList/index.js b/src/components/KeyboardDismissingFlatList/index.js
deleted file mode 100644
index 0ca8504d96ab..000000000000
--- a/src/components/KeyboardDismissingFlatList/index.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import React, {useRef, useEffect, useCallback} from 'react';
-import {FlatList, Keyboard} from 'react-native';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-
-function KeyboardDismissingFlatList(props) {
- const isScreenTouched = useRef(false);
-
- useEffect(() => {
- if (!DeviceCapabilities.canUseTouchScreen()) {
- return;
- }
-
- const touchStart = () => {
- isScreenTouched.current = true;
- };
-
- const touchEnd = () => {
- isScreenTouched.current = false;
- };
-
- // We're setting `isScreenTouched` in this listener only for web platforms with touchscreen (mWeb) where
- // we want to dismiss the keyboard only when the list is scrolled by the user and not when it's scrolled programmatically.
- document.addEventListener('touchstart', touchStart);
- document.addEventListener('touchend', touchEnd);
-
- return () => {
- document.removeEventListener('touchstart', touchStart);
- document.removeEventListener('touchend', touchEnd);
- };
- }, []);
-
- const onScroll = useCallback(() => {
- // Only dismiss the keyboard whenever the user scrolls the screen
- if (!isScreenTouched.current) {
- return;
- }
- Keyboard.dismiss();
- }, []);
-
- return (
-
- );
-}
-
-KeyboardDismissingFlatList.displayName = 'KeyboardDismissingFlatList';
-
-export default KeyboardDismissingFlatList;
diff --git a/src/components/KeyboardDismissingFlatList/index.native.js b/src/components/KeyboardDismissingFlatList/index.native.js
deleted file mode 100644
index 97297528ac77..000000000000
--- a/src/components/KeyboardDismissingFlatList/index.native.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import React from 'react';
-import {FlatList, Keyboard} from 'react-native';
-
-function KeyboardDismissingFlatList(props) {
- return (
- Keyboard.dismiss()}
- />
- );
-}
-
-KeyboardDismissingFlatList.displayName = 'KeyboardDismissingFlatList';
-
-export default KeyboardDismissingFlatList;
diff --git a/src/components/KeyboardSpacer/BaseKeyboardSpacer.js b/src/components/KeyboardSpacer/BaseKeyboardSpacer.js
index 2066f3492373..adab3e2ea66d 100644
--- a/src/components/KeyboardSpacer/BaseKeyboardSpacer.js
+++ b/src/components/KeyboardSpacer/BaseKeyboardSpacer.js
@@ -1,7 +1,7 @@
-import React, {useState, useEffect, useCallback} from 'react';
+import React, {useCallback, useEffect, useState} from 'react';
import {Dimensions, Keyboard, View} from 'react-native';
-import * as StyleUtils from '../../styles/StyleUtils';
-import {propTypes, defaultProps} from './BaseKeyboardSpacerPropTypes';
+import * as StyleUtils from '@styles/StyleUtils';
+import {defaultProps, propTypes} from './BaseKeyboardSpacerPropTypes';
function BaseKeyboardSpacer(props) {
const [keyboardSpace, setKeyboardSpace] = useState(0);
diff --git a/src/components/KeyboardSpacer/index.android.js b/src/components/KeyboardSpacer/index.android.js
index 15755be70e31..d7c57f7d73c2 100644
--- a/src/components/KeyboardSpacer/index.android.js
+++ b/src/components/KeyboardSpacer/index.android.js
@@ -3,9 +3,9 @@
* view up with the keyboard allowing the user to see what they are typing.
*/
import React from 'react';
-import StatusBar from '../../libs/StatusBar';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import StatusBar from '@libs/StatusBar';
import BaseKeyboardSpacer from './BaseKeyboardSpacer';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
function KeyboardSpacer() {
return (
diff --git a/src/components/KeyboardSpacer/index.ios.js b/src/components/KeyboardSpacer/index.ios.js
index 63cae305c362..612ef75c290f 100644
--- a/src/components/KeyboardSpacer/index.ios.js
+++ b/src/components/KeyboardSpacer/index.ios.js
@@ -3,10 +3,10 @@
* keyboard allowing the user to see what they are typing.
*/
import React from 'react';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import BaseKeyboardSpacer from './BaseKeyboardSpacer';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
-import * as StyleUtils from '../../styles/StyleUtils';
-import CONST from '../../CONST';
function KeyboardSpacer(props) {
return (
diff --git a/src/components/LHNOptionsList/LHNOptionsList.js b/src/components/LHNOptionsList/LHNOptionsList.js
index 5e07b487c4f7..a06b3314e5a9 100644
--- a/src/components/LHNOptionsList/LHNOptionsList.js
+++ b/src/components/LHNOptionsList/LHNOptionsList.js
@@ -2,9 +2,9 @@ import PropTypes from 'prop-types';
import React from 'react';
import {FlatList, View} from 'react-native';
import _ from 'underscore';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import OptionRowLHNDataWithFocus from './OptionRowLHNDataWithFocus';
const propTypes = {
diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js
index 2b992e462e34..f83e0b834287 100644
--- a/src/components/LHNOptionsList/OptionRowLHN.js
+++ b/src/components/LHNOptionsList/OptionRowLHN.js
@@ -1,34 +1,34 @@
-import _ from 'underscore';
-import React, {useState, useRef, useCallback} from 'react';
-import PropTypes from 'prop-types';
-import {View, StyleSheet} from 'react-native';
-import lodashGet from 'lodash/get';
import {useFocusEffect} from '@react-navigation/native';
-import * as optionRowStyles from '../../styles/optionRowStyles';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
-import DateUtils from '../../libs/DateUtils';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import MultipleAvatars from '../MultipleAvatars';
-import Hoverable from '../Hoverable';
-import DisplayNames from '../DisplayNames';
-import Text from '../Text';
-import SubscriptAvatar from '../SubscriptAvatar';
-import CONST from '../../CONST';
-import themeColors from '../../styles/themes/default';
-import OfflineWithFeedback from '../OfflineWithFeedback';
-import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction';
-import * as ReportActionContextMenu from '../../pages/home/report/ContextMenu/ReportActionContextMenu';
-import * as ContextMenuActions from '../../pages/home/report/ContextMenu/ContextMenuActions';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import useLocalize from '../../hooks/useLocalize';
-import Permissions from '../../libs/Permissions';
-import Tooltip from '../Tooltip';
-import DomUtils from '../../libs/DomUtils';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import ReportActionComposeFocusManager from '../../libs/ReportActionComposeFocusManager';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useRef, useState} from 'react';
+import {StyleSheet, View} from 'react-native';
+import _ from 'underscore';
+import DisplayNames from '@components/DisplayNames';
+import Hoverable from '@components/Hoverable';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MultipleAvatars from '@components/MultipleAvatars';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import SubscriptAvatar from '@components/SubscriptAvatar';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import DateUtils from '@libs/DateUtils';
+import DomUtils from '@libs/DomUtils';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as ContextMenuActions from '@pages/home/report/ContextMenu/ContextMenuActions';
+import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
+import * as optionRowStyles from '@styles/optionRowStyles';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
const propTypes = {
/** Style for hovered state */
diff --git a/src/components/LHNOptionsList/OptionRowLHNData.js b/src/components/LHNOptionsList/OptionRowLHNData.js
index e93e3690138e..ebba2ffe0587 100644
--- a/src/components/LHNOptionsList/OptionRowLHNData.js
+++ b/src/components/LHNOptionsList/OptionRowLHNData.js
@@ -1,21 +1,20 @@
-import {withOnyx} from 'react-native-onyx';
+import {deepEqual} from 'fast-equals';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
import PropTypes from 'prop-types';
-import React, {useEffect, useRef, useMemo} from 'react';
-import {deepEqual} from 'fast-equals';
-import SidebarUtils from '../../libs/SidebarUtils';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import OptionRowLHN, {propTypes as basePropTypes, defaultProps as baseDefaultProps} from './OptionRowLHN';
-import * as Report from '../../libs/actions/Report';
-import * as UserUtils from '../../libs/UserUtils';
-import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
-import * as TransactionUtils from '../../libs/TransactionUtils';
-
-import participantPropTypes from '../participantPropTypes';
-import CONST from '../../CONST';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
+import React, {useEffect, useMemo, useRef} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import participantPropTypes from '@components/participantPropTypes';
+import compose from '@libs/compose';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import SidebarUtils from '@libs/SidebarUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import * as UserUtils from '@libs/UserUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import OptionRowLHN, {defaultProps as baseDefaultProps, propTypes as basePropTypes} from './OptionRowLHN';
const propTypes = {
/** Whether row should be focused */
diff --git a/src/components/LHNOptionsList/OptionRowLHNDataWithFocus.js b/src/components/LHNOptionsList/OptionRowLHNDataWithFocus.js
index 5e58be79e088..67e90bcbb0e0 100644
--- a/src/components/LHNOptionsList/OptionRowLHNDataWithFocus.js
+++ b/src/components/LHNOptionsList/OptionRowLHNDataWithFocus.js
@@ -1,6 +1,6 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDefaultProps} from '../withCurrentReportID';
+import React from 'react';
+import withCurrentReportID, {withCurrentReportIDDefaultProps, withCurrentReportIDPropTypes} from '@components/withCurrentReportID';
import OptionRowLHNData from './OptionRowLHNData';
const propTypes = {
diff --git a/src/components/LocaleContextProvider.js b/src/components/LocaleContextProvider.js
index b8838f253e74..5fbb7716befe 100644
--- a/src/components/LocaleContextProvider.js
+++ b/src/components/LocaleContextProvider.js
@@ -1,17 +1,16 @@
-import React, {createContext, useMemo} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {createContext, useMemo} from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-
-import ONYXKEYS from '../ONYXKEYS';
-import * as Localize from '../libs/Localize';
-import DateUtils from '../libs/DateUtils';
-import * as NumberFormatUtils from '../libs/NumberFormatUtils';
-import * as LocaleDigitUtils from '../libs/LocaleDigitUtils';
-import CONST from '../CONST';
-import compose from '../libs/compose';
+import compose from '@libs/compose';
+import DateUtils from '@libs/DateUtils';
+import * as LocaleDigitUtils from '@libs/LocaleDigitUtils';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import * as Localize from '@libs/Localize';
+import * as NumberFormatUtils from '@libs/NumberFormatUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import withCurrentUserPersonalDetails from './withCurrentUserPersonalDetails';
-import * as LocalePhoneNumber from '../libs/LocalePhoneNumber';
const LocaleContext = createContext(null);
diff --git a/src/components/LocalePicker.js b/src/components/LocalePicker.js
index 435f88e51e53..2c5a6e7b7ec6 100644
--- a/src/components/LocalePicker.js
+++ b/src/components/LocalePicker.js
@@ -1,15 +1,15 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import compose from '../libs/compose';
-import * as App from '../libs/actions/App';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
+import _ from 'underscore';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as App from '@userActions/App';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import Picker from './Picker';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** Indicates which locale the user currently has selected */
diff --git a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js b/src/components/LocationErrorMessage/BaseLocationErrorMessage.js
index 3a638f3e999e..786588993cd8 100644
--- a/src/components/LocationErrorMessage/BaseLocationErrorMessage.js
+++ b/src/components/LocationErrorMessage/BaseLocationErrorMessage.js
@@ -1,16 +1,16 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import CONST from '../../CONST';
-import colors from '../../styles/colors';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import Text from '../Text';
-import TextLink from '../TextLink';
-import Tooltip from '../Tooltip';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import Tooltip from '@components/Tooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import colors from '@styles/colors';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes';
const propTypes = {
diff --git a/src/components/LocationErrorMessage/index.js b/src/components/LocationErrorMessage/index.js
index e8ec402401cf..60fb4489799e 100644
--- a/src/components/LocationErrorMessage/index.js
+++ b/src/components/LocationErrorMessage/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import {Linking} from 'react-native';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import BaseLocationErrorMessage from './BaseLocationErrorMessage';
import * as locationErrorMessagePropTypes from './locationErrorMessagePropTypes';
diff --git a/src/components/Lottie/Lottie.tsx b/src/components/Lottie/Lottie.tsx
index 97c7e8fffdd1..cf689224278f 100644
--- a/src/components/Lottie/Lottie.tsx
+++ b/src/components/Lottie/Lottie.tsx
@@ -1,6 +1,6 @@
-import React, {forwardRef} from 'react';
import LottieView, {LottieViewProps} from 'lottie-react-native';
-import styles from '../../styles/styles';
+import React, {forwardRef} from 'react';
+import styles from '@styles/styles';
const Lottie = forwardRef((props: LottieViewProps, ref) => (
(
-
- )),
-);
+const MagicCodeInputWithRef = forwardRef((props, ref) => (
+
+));
+
+MagicCodeInputWithRef.displayName = 'MagicCodeInputWithRef';
+
+export default withNetwork()(MagicCodeInputWithRef);
diff --git a/src/components/MapView/Direction.tsx b/src/components/MapView/Direction.tsx
index 920a3912dca4..1c675ccfc4d6 100644
--- a/src/components/MapView/Direction.tsx
+++ b/src/components/MapView/Direction.tsx
@@ -1,6 +1,6 @@
import Mapbox from '@rnmapbox/maps';
+import styles from '@styles/styles';
import {DirectionProps} from './MapViewTypes';
-import styles from '../../styles/styles';
function Direction({coordinates}: DirectionProps) {
if (coordinates.length < 1) {
diff --git a/src/components/MapView/Direction.web.tsx b/src/components/MapView/Direction.web.tsx
index 190ecb03cb5e..c4cf74176aba 100644
--- a/src/components/MapView/Direction.web.tsx
+++ b/src/components/MapView/Direction.web.tsx
@@ -2,14 +2,12 @@
// This is why we have separate components for web and native to handle the specific implementations.
// For the web version, we use the Mapbox Web library called react-map-gl, while for the native mobile version,
// we utilize a different Mapbox library @rnmapbox/maps tailored for mobile development.
-
import React from 'react';
-import {View} from 'react-native';
import {Layer, Source} from 'react-map-gl';
+import {View} from 'react-native';
+import styles from '@styles/styles';
import {DirectionProps} from './MapViewTypes';
-import styles from '../../styles/styles';
-
function Direction({coordinates}: DirectionProps) {
const layerLayoutStyle: Record = styles.mapDirectionLayer.layout;
const layerPointStyle: Record = styles.mapDirectionLayer.paint;
diff --git a/src/components/MapView/MapView.tsx b/src/components/MapView/MapView.tsx
index 5f791112da62..c91dc63a3bd1 100644
--- a/src/components/MapView/MapView.tsx
+++ b/src/components/MapView/MapView.tsx
@@ -1,15 +1,13 @@
-import {View} from 'react-native';
import {useFocusEffect, useNavigation} from '@react-navigation/native';
import Mapbox, {MapState, MarkerView, setAccessToken} from '@rnmapbox/maps';
import {forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
-import styles from '../../styles/styles';
-
+import {View} from 'react-native';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import Direction from './Direction';
+import {MapViewHandle, MapViewProps} from './MapViewTypes';
import responder from './responder';
import utils from './utils';
-import Direction from './Direction';
-import CONST from '../../CONST';
-
-import {MapViewProps, MapViewHandle} from './MapViewTypes';
const MapView = forwardRef(({accessToken, style, mapPadding, styleURL, pitchEnabled, initialState, waypoints, directionCoordinates, onMapReady}, ref) => {
const cameraRef = useRef(null);
diff --git a/src/components/MapView/MapView.web.tsx b/src/components/MapView/MapView.web.tsx
index 78c5a9175594..fe240c1f5121 100644
--- a/src/components/MapView/MapView.web.tsx
+++ b/src/components/MapView/MapView.web.tsx
@@ -2,22 +2,18 @@
// This is why we have separate components for web and native to handle the specific implementations.
// For the web version, we use the Mapbox Web library called react-map-gl, while for the native mobile version,
// we utilize a different Mapbox library @rnmapbox/maps tailored for mobile development.
-
+import mapboxgl from 'mapbox-gl';
+import 'mapbox-gl/dist/mapbox-gl.css';
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useState} from 'react';
-import {View} from 'react-native';
import Map, {MapRef, Marker} from 'react-map-gl';
-import mapboxgl from 'mapbox-gl';
-
-import responder from './responder';
-import utils from './utils';
-
-import CONST from '../../CONST';
-import * as StyleUtils from '../../styles/StyleUtils';
-import themeColors from '../../styles/themes/default';
+import {View} from 'react-native';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import Direction from './Direction';
import {MapViewHandle, MapViewProps} from './MapViewTypes';
-
-import 'mapbox-gl/dist/mapbox-gl.css';
+import responder from './responder';
+import utils from './utils';
const MapView = forwardRef(
({style, styleURL, waypoints, mapPadding, accessToken, directionCoordinates, initialState = {location: CONST.MAPBOX.DEFAULT_COORDINATE, zoom: CONST.MAPBOX.DEFAULT_ZOOM}}, ref) => {
diff --git a/src/components/MapView/PendingMapView.tsx b/src/components/MapView/PendingMapView.tsx
index d97d4aaee16f..8a6799035fec 100644
--- a/src/components/MapView/PendingMapView.tsx
+++ b/src/components/MapView/PendingMapView.tsx
@@ -1,12 +1,12 @@
+import _ from 'lodash';
import React from 'react';
import {View} from 'react-native';
-import _ from 'lodash';
-import variables from '../../styles/variables';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
import {PendingMapViewProps} from './MapViewTypes';
-import BlockingView from '../BlockingViews/BlockingView';
-import * as Expensicons from '../Icon/Expensicons';
function PendingMapView({title = '', subtitle = '', style}: PendingMapViewProps) {
const hasTextContent = !_.isEmpty(title) || !_.isEmpty(subtitle);
diff --git a/src/components/MapView/responder/index.ts b/src/components/MapView/responder/index.ts
index c4c325444f70..f417f7769ae8 100644
--- a/src/components/MapView/responder/index.ts
+++ b/src/components/MapView/responder/index.ts
@@ -1,3 +1,3 @@
-import SwipeInterceptPanResponder from '../../SwipeInterceptPanResponder';
+import SwipeInterceptPanResponder from '@components/SwipeInterceptPanResponder';
export default SwipeInterceptPanResponder;
diff --git a/src/components/MentionSuggestions.js b/src/components/MentionSuggestions.js
index 6c0803ca9d64..d18b8947e68d 100644
--- a/src/components/MentionSuggestions.js
+++ b/src/components/MentionSuggestions.js
@@ -1,16 +1,16 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import * as StyleUtils from '../styles/StyleUtils';
-import Text from './Text';
-import CONST from '../CONST';
-import Avatar from './Avatar';
+import getStyledTextArray from '@libs/GetStyledTextArray';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
-import getStyledTextArray from '../libs/GetStyledTextArray';
+import Avatar from './Avatar';
import avatarPropTypes from './avatarPropTypes';
+import Text from './Text';
const propTypes = {
/** The index of the highlighted mention */
diff --git a/src/components/MenuItem.js b/src/components/MenuItem.js
index 16181ee00abb..08535f1724fb 100644
--- a/src/components/MenuItem.js
+++ b/src/components/MenuItem.js
@@ -1,30 +1,31 @@
-import _ from 'underscore';
+import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import React, {useEffect, useMemo} from 'react';
import {View} from 'react-native';
-import ExpensiMark from 'expensify-common/lib/ExpensiMark';
-import Text from './Text';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import * as StyleUtils from '../styles/StyleUtils';
-import Icon from './Icon';
-import * as Expensicons from './Icon/Expensicons';
-import getButtonState from '../libs/getButtonState';
-import convertToLTR from '../libs/convertToLTR';
+import _ from 'underscore';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import ControlSelection from '@libs/ControlSelection';
+import convertToLTR from '@libs/convertToLTR';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
import Avatar from './Avatar';
import Badge from './Badge';
-import CONST from '../CONST';
+import DisplayNames from './DisplayNames';
+import Hoverable from './Hoverable';
+import Icon from './Icon';
+import * as Expensicons from './Icon/Expensicons';
+import * as defaultWorkspaceAvatars from './Icon/WorkspaceDefaultAvatars';
import menuItemPropTypes from './menuItemPropTypes';
-import SelectCircle from './SelectCircle';
import MultipleAvatars from './MultipleAvatars';
-import * as defaultWorkspaceAvatars from './Icon/WorkspaceDefaultAvatars';
import PressableWithSecondaryInteraction from './PressableWithSecondaryInteraction';
-import * as DeviceCapabilities from '../libs/DeviceCapabilities';
-import ControlSelection from '../libs/ControlSelection';
-import variables from '../styles/variables';
-import * as Session from '../libs/actions/Session';
-import Hoverable from './Hoverable';
-import useWindowDimensions from '../hooks/useWindowDimensions';
import RenderHTML from './RenderHTML';
+import SelectCircle from './SelectCircle';
+import Text from './Text';
const propTypes = menuItemPropTypes;
@@ -79,6 +80,7 @@ const defaultProps = {
shouldRenderAsHTML: false,
rightComponent: undefined,
shouldShowRightComponent: false,
+ titleWithTooltips: [],
shouldCheckActionAllowedOnPress: true,
};
@@ -137,6 +139,21 @@ const MenuItem = React.forwardRef((props, ref) => {
const hasPressableRightComponent = props.iconRight || (props.rightComponent && props.shouldShowRightComponent);
+ const renderTitleContent = () => {
+ if (props.titleWithTooltips && _.isArray(props.titleWithTooltips) && props.titleWithTooltips.length > 0) {
+ return (
+
+ );
+ }
+
+ return convertToLTR(props.title);
+ };
+
const onPressAction = (e) => {
if (props.disabled || !props.interactive) {
return;
@@ -266,7 +283,7 @@ const MenuItem = React.forwardRef((props, ref) => {
numberOfLines={props.numberOfLinesTitle || undefined}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: props.interactive && props.disabled}}
>
- {convertToLTR(props.title)}
+ {renderTitleContent()}
)}
{Boolean(props.shouldShowTitleIcon) && (
diff --git a/src/components/MenuItemList.js b/src/components/MenuItemList.js
index 90f863ba2bc7..b9f2e6fc228b 100644
--- a/src/components/MenuItemList.js
+++ b/src/components/MenuItemList.js
@@ -1,21 +1,27 @@
+import PropTypes from 'prop-types';
import React from 'react';
import _ from 'underscore';
-import PropTypes from 'prop-types';
+import useSingleExecution from '@hooks/useSingleExecution';
+import {CONTEXT_MENU_TYPES} from '@pages/home/report/ContextMenu/ContextMenuActions';
+import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
import MenuItem from './MenuItem';
import menuItemPropTypes from './menuItemPropTypes';
-import * as ReportActionContextMenu from '../pages/home/report/ContextMenu/ReportActionContextMenu';
-import {CONTEXT_MENU_TYPES} from '../pages/home/report/ContextMenu/ContextMenuActions';
const propTypes = {
/** An array of props that are pass to individual MenuItem components */
menuItems: PropTypes.arrayOf(PropTypes.shape(menuItemPropTypes)),
+
+ /** Whether or not to use the single execution hook */
+ shouldUseSingleExecution: PropTypes.bool,
};
const defaultProps = {
menuItems: [],
+ shouldUseSingleExecution: false,
};
function MenuItemList(props) {
let popoverAnchor;
+ const {isExecuting, singleExecution} = useSingleExecution();
/**
* Handle the secondary interaction for a menu item.
@@ -41,6 +47,8 @@ function MenuItemList(props) {
shouldBlockSelection={Boolean(menuItemProps.link)}
// eslint-disable-next-line react/jsx-props-no-spreading
{...menuItemProps}
+ disabled={menuItemProps.disabled || isExecuting}
+ onPress={props.shouldUseSingleExecution ? singleExecution(menuItemProps.onPress) : menuItemProps.onPress}
/>
))}
>
diff --git a/src/components/MenuItemWithTopDescription.js b/src/components/MenuItemWithTopDescription.js
index ee51d2f41ccd..8215b7eb3a19 100644
--- a/src/components/MenuItemWithTopDescription.js
+++ b/src/components/MenuItemWithTopDescription.js
@@ -1,6 +1,6 @@
import React from 'react';
-import menuItemPropTypes from './menuItemPropTypes';
import MenuItem from './MenuItem';
+import menuItemPropTypes from './menuItemPropTypes';
const propTypes = menuItemPropTypes;
@@ -19,10 +19,14 @@ function MenuItemWithTopDescription(props) {
MenuItemWithTopDescription.propTypes = propTypes;
MenuItemWithTopDescription.displayName = 'MenuItemWithTopDescription';
-export default React.forwardRef((props, ref) => (
+const MenuItemWithTopDescriptionWithRef = React.forwardRef((props, ref) => (
));
+
+MenuItemWithTopDescriptionWithRef.displayName = 'MenuItemWithTopDescriptionWithRef';
+
+export default MenuItemWithTopDescriptionWithRef;
diff --git a/src/components/MessagesRow.js b/src/components/MessagesRow.js
new file mode 100644
index 000000000000..b843e0dfa61e
--- /dev/null
+++ b/src/components/MessagesRow.js
@@ -0,0 +1,73 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
+import DotIndicatorMessage from './DotIndicatorMessage';
+import Icon from './Icon';
+import * as Expensicons from './Icon/Expensicons';
+import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
+import Tooltip from './Tooltip';
+
+const propTypes = {
+ /* The messages to display */
+ messages: PropTypes.objectOf(PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string, PropTypes.object]))])),
+
+ /* The type of message, 'error' shows a red dot, 'success' shows a green dot */
+ type: PropTypes.oneOf(['error', 'success']).isRequired,
+
+ /** A function to run when the X button next to the message is clicked */
+ onClose: PropTypes.func,
+
+ /** Additional style object for the container */
+ containerStyles: stylePropTypes,
+
+ /** Whether we can dismiss the messages */
+ canDismiss: PropTypes.bool,
+};
+
+const defaultProps = {
+ messages: {},
+ onClose: () => {},
+ containerStyles: [],
+ canDismiss: true,
+};
+
+function MessagesRow({messages, type, onClose, containerStyles, canDismiss}) {
+ const {translate} = useLocalize();
+ if (_.isEmpty(messages)) {
+ return null;
+ }
+
+ return (
+
+
+ {canDismiss && (
+
+
+
+
+
+ )}
+
+ );
+}
+
+MessagesRow.propTypes = propTypes;
+MessagesRow.defaultProps = defaultProps;
+MessagesRow.displayName = 'MessagesRow';
+
+export default MessagesRow;
diff --git a/src/components/Modal/BaseModal.js b/src/components/Modal/BaseModal.js
index 051c4ba3f80a..6ed3b16c676d 100644
--- a/src/components/Modal/BaseModal.js
+++ b/src/components/Modal/BaseModal.js
@@ -1,20 +1,20 @@
+import PropTypes from 'prop-types';
import React, {forwardRef, useCallback, useEffect, useMemo, useRef} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import ReactNativeModal from 'react-native-modal';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
-import styles from '../../styles/styles';
-import * as Modal from '../../libs/actions/Modal';
-import * as StyleUtils from '../../styles/StyleUtils';
-import themeColors from '../../styles/themes/default';
-import {propTypes as modalPropTypes, defaultProps as modalDefaultProps} from './modalPropTypes';
-import getModalStyles from '../../styles/getModalStyles';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import variables from '../../styles/variables';
-import CONST from '../../CONST';
-import ComposerFocusManager from '../../libs/ComposerFocusManager';
-import useNativeDriver from '../../libs/useNativeDriver';
-import usePrevious from '../../hooks/usePrevious';
+import usePrevious from '@hooks/usePrevious';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import ComposerFocusManager from '@libs/ComposerFocusManager';
+import useNativeDriver from '@libs/useNativeDriver';
+import getModalStyles from '@styles/getModalStyles';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import * as Modal from '@userActions/Modal';
+import CONST from '@src/CONST';
+import {defaultProps as modalDefaultProps, propTypes as modalPropTypes} from './modalPropTypes';
const propTypes = {
...modalPropTypes,
@@ -219,10 +219,14 @@ BaseModal.propTypes = propTypes;
BaseModal.defaultProps = defaultProps;
BaseModal.displayName = 'BaseModal';
-export default forwardRef((props, ref) => (
+const BaseModalWithRef = forwardRef((props, ref) => (
));
+
+BaseModalWithRef.displayName = 'BaseModalWithRef';
+
+export default BaseModalWithRef;
diff --git a/src/components/Modal/index.android.js b/src/components/Modal/index.android.js
index b5f11a02650a..51745ae6a20f 100644
--- a/src/components/Modal/index.android.js
+++ b/src/components/Modal/index.android.js
@@ -1,9 +1,9 @@
import React from 'react';
import {AppState} from 'react-native';
-import withWindowDimensions from '../withWindowDimensions';
+import withWindowDimensions from '@components/withWindowDimensions';
+import ComposerFocusManager from '@libs/ComposerFocusManager';
import BaseModal from './BaseModal';
-import {propTypes, defaultProps} from './modalPropTypes';
-import ComposerFocusManager from '../../libs/ComposerFocusManager';
+import {defaultProps, propTypes} from './modalPropTypes';
AppState.addEventListener('focus', () => {
ComposerFocusManager.setReadyToFocus();
diff --git a/src/components/Modal/index.ios.js b/src/components/Modal/index.ios.js
index d8206d12532d..38f477e2049b 100644
--- a/src/components/Modal/index.ios.js
+++ b/src/components/Modal/index.ios.js
@@ -1,7 +1,7 @@
import React from 'react';
-import withWindowDimensions from '../withWindowDimensions';
+import withWindowDimensions from '@components/withWindowDimensions';
import BaseModal from './BaseModal';
-import {propTypes, defaultProps} from './modalPropTypes';
+import {defaultProps, propTypes} from './modalPropTypes';
function Modal(props) {
return (
diff --git a/src/components/Modal/index.web.js b/src/components/Modal/index.web.js
index 065b3a9f210f..3bea0eb58aa9 100644
--- a/src/components/Modal/index.web.js
+++ b/src/components/Modal/index.web.js
@@ -1,11 +1,11 @@
import React, {useState} from 'react';
-import withWindowDimensions from '../withWindowDimensions';
+import withWindowDimensions from '@components/withWindowDimensions';
+import StatusBar from '@libs/StatusBar';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import BaseModal from './BaseModal';
-import {propTypes, defaultProps} from './modalPropTypes';
-import * as StyleUtils from '../../styles/StyleUtils';
-import themeColors from '../../styles/themes/default';
-import StatusBar from '../../libs/StatusBar';
-import CONST from '../../CONST';
+import {defaultProps, propTypes} from './modalPropTypes';
function Modal(props) {
const [previousStatusBarColor, setPreviousStatusBarColor] = useState();
diff --git a/src/components/Modal/modalPropTypes.js b/src/components/Modal/modalPropTypes.js
index 58de5a6c57ca..84e610b694e4 100644
--- a/src/components/Modal/modalPropTypes.js
+++ b/src/components/Modal/modalPropTypes.js
@@ -1,8 +1,8 @@
import PropTypes from 'prop-types';
import _ from 'underscore';
-import CONST from '../../CONST';
-import {windowDimensionsPropTypes} from '../withWindowDimensions';
-import stylePropTypes from '../../styles/stylePropTypes';
+import {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import stylePropTypes from '@styles/stylePropTypes';
+import CONST from '@src/CONST';
const propTypes = {
/** Decides whether the modal should cover fullscreen. FullScreen modal has backdrop */
diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.js
index ab0b77c21653..a8fb5390ebb6 100644
--- a/src/components/MoneyReportHeader.js
+++ b/src/components/MoneyReportHeader.js
@@ -1,28 +1,28 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
-import _ from 'underscore';
-import {withOnyx} from 'react-native-onyx';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import useLocalize from '../hooks/useLocalize';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import iouReportPropTypes from '@pages/iouReportPropTypes';
+import nextStepPropTypes from '@pages/nextStepPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import Button from './Button';
import HeaderWithBackButton from './HeaderWithBackButton';
-import iouReportPropTypes from '../pages/iouReportPropTypes';
-import * as ReportUtils from '../libs/ReportUtils';
-import participantPropTypes from './participantPropTypes';
-import styles from '../styles/styles';
-import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-import compose from '../libs/compose';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
import MoneyReportHeaderStatusBar from './MoneyReportHeaderStatusBar';
+import participantPropTypes from './participantPropTypes';
import SettlementButton from './SettlementButton';
-import Button from './Button';
-import * as IOU from '../libs/actions/IOU';
-import * as CurrencyUtils from '../libs/CurrencyUtils';
-import reportPropTypes from '../pages/reportPropTypes';
-import nextStepPropTypes from '../pages/nextStepPropTypes';
+import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
const propTypes = {
/** The report currently being looked at */
diff --git a/src/components/MoneyReportHeaderStatusBar.js b/src/components/MoneyReportHeaderStatusBar.js
index 9c4362b620d1..db6502aa0119 100644
--- a/src/components/MoneyReportHeaderStatusBar.js
+++ b/src/components/MoneyReportHeaderStatusBar.js
@@ -1,10 +1,10 @@
import React, {useMemo} from 'react';
import {Text, View} from 'react-native';
import _ from 'underscore';
-import styles from '../styles/styles';
-import * as NextStepUtils from '../libs/NextStepUtils';
-import useLocalize from '../hooks/useLocalize';
-import nextStepPropTypes from '../pages/nextStepPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import * as NextStepUtils from '@libs/NextStepUtils';
+import nextStepPropTypes from '@pages/nextStepPropTypes';
+import styles from '@styles/styles';
import RenderHTML from './RenderHTML';
const propTypes = {
diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js
index 0b266351a60c..b60e950b2bbf 100755
--- a/src/components/MoneyRequestConfirmationList.js
+++ b/src/components/MoneyRequestConfirmationList.js
@@ -1,49 +1,49 @@
-import React, {useCallback, useMemo, useReducer, useState, useEffect} from 'react';
+import {useIsFocused} from '@react-navigation/native';
+import {format} from 'date-fns';
+import {isEmpty} from 'lodash';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useReducer, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import {format} from 'date-fns';
import _ from 'underscore';
-import {View} from 'react-native';
-import lodashGet from 'lodash/get';
-import {useIsFocused} from '@react-navigation/native';
-import {isEmpty} from 'lodash';
-import Text from './Text';
-import styles from '../styles/styles';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import Permissions from '../libs/Permissions';
-import OptionsSelector from './OptionsSelector';
-import ONYXKEYS from '../ONYXKEYS';
-import compose from '../libs/compose';
-import CONST from '../CONST';
-import ButtonWithDropdownMenu from './ButtonWithDropdownMenu';
-import Log from '../libs/Log';
-import SettlementButton from './SettlementButton';
-import ROUTES from '../ROUTES';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from './withCurrentUserPersonalDetails';
-import * as IOUUtils from '../libs/IOUUtils';
-import MenuItemWithTopDescription from './MenuItemWithTopDescription';
-import Navigation from '../libs/Navigation/Navigation';
-import optionPropTypes from './optionPropTypes';
-import * as CurrencyUtils from '../libs/CurrencyUtils';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import DistanceRequestUtils from '@libs/DistanceRequestUtils';
+import * as IOUUtils from '@libs/IOUUtils';
+import Log from '@libs/Log';
+import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReceiptUtils from '@libs/ReceiptUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import Button from './Button';
+import ButtonWithDropdownMenu from './ButtonWithDropdownMenu';
+import categoryPropTypes from './categoryPropTypes';
+import ConfirmedRoute from './ConfirmedRoute';
+import FormHelpMessage from './FormHelpMessage';
import * as Expensicons from './Icon/Expensicons';
-import themeColors from '../styles/themes/default';
import Image from './Image';
-import useLocalize from '../hooks/useLocalize';
-import * as ReceiptUtils from '../libs/ReceiptUtils';
-import categoryPropTypes from './categoryPropTypes';
+import MenuItemWithTopDescription from './MenuItemWithTopDescription';
+import optionPropTypes from './optionPropTypes';
+import OptionsSelector from './OptionsSelector';
+import SettlementButton from './SettlementButton';
import Switch from './Switch';
import tagPropTypes from './tagPropTypes';
-import ConfirmedRoute from './ConfirmedRoute';
+import Text from './Text';
import transactionPropTypes from './transactionPropTypes';
-import DistanceRequestUtils from '../libs/DistanceRequestUtils';
-import FormHelpMessage from './FormHelpMessage';
-import * as IOU from '../libs/actions/IOU';
-import * as TransactionUtils from '../libs/TransactionUtils';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import * as MoneyRequestUtils from '../libs/MoneyRequestUtils';
-import {iouDefaultProps, iouPropTypes} from '../pages/iou/propTypes';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from './withCurrentUserPersonalDetails';
const propTypes = {
/** Callback to inform parent modal of success */
@@ -225,8 +225,7 @@ function MoneyRequestConfirmationList(props) {
const shouldCalculateDistanceAmount = props.isDistanceRequest && props.iouAmount === 0;
// A flag for showing the categories field
- const shouldShowCategories =
- props.isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && (props.iouCategory || OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories)));
+ const shouldShowCategories = props.isPolicyExpenseChat && (props.iouCategory || OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories)));
// A flag and a toggler for showing the rest of the form fields
const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false);
diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js
index 086e1429baef..cbadbf40ff5c 100644
--- a/src/components/MoneyRequestHeader.js
+++ b/src/components/MoneyRequestHeader.js
@@ -1,29 +1,29 @@
-import React, {useState, useCallback, useEffect} from 'react';
-import {withOnyx} from 'react-native-onyx';
-import {View} from 'react-native';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useState} from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import compose from '@libs/compose';
+import * as HeaderUtils from '@libs/HeaderUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import iouReportPropTypes from '@pages/iouReportPropTypes';
+import styles from '@styles/styles';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import ConfirmModal from './ConfirmModal';
import HeaderWithBackButton from './HeaderWithBackButton';
-import iouReportPropTypes from '../pages/iouReportPropTypes';
-import * as ReportUtils from '../libs/ReportUtils';
-import compose from '../libs/compose';
import * as Expensicons from './Icon/Expensicons';
-import participantPropTypes from './participantPropTypes';
-import styles from '../styles/styles';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import * as IOU from '../libs/actions/IOU';
-import ConfirmModal from './ConfirmModal';
-import useLocalize from '../hooks/useLocalize';
import MoneyRequestHeaderStatusBar from './MoneyRequestHeaderStatusBar';
-import * as TransactionUtils from '../libs/TransactionUtils';
-import * as ReportActionsUtils from '../libs/ReportActionsUtils';
-import * as HeaderUtils from '../libs/HeaderUtils';
-import reportActionPropTypes from '../pages/home/report/reportActionPropTypes';
+import participantPropTypes from './participantPropTypes';
import transactionPropTypes from './transactionPropTypes';
-import useWindowDimensions from '../hooks/useWindowDimensions';
const propTypes = {
/** The report currently being looked at */
diff --git a/src/components/MoneyRequestHeaderStatusBar.js b/src/components/MoneyRequestHeaderStatusBar.js
index 31a6e9c0e897..f217d7fc2426 100644
--- a/src/components/MoneyRequestHeaderStatusBar.js
+++ b/src/components/MoneyRequestHeaderStatusBar.js
@@ -1,7 +1,7 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
import Text from './Text';
const propTypes = {
diff --git a/src/components/MoneyRequestSkeletonView.js b/src/components/MoneyRequestSkeletonView.js
index 50a7b56b91e3..e03cb78972cf 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 {Rect} from 'react-native-svg';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
function MoneyRequestSkeletonView() {
return (
diff --git a/src/components/MultipleAvatars.js b/src/components/MultipleAvatars.js
index 8866d61d3870..85b6f7995693 100644
--- a/src/components/MultipleAvatars.js
+++ b/src/components/MultipleAvatars.js
@@ -1,16 +1,16 @@
-import React, {memo, useMemo} from 'react';
import PropTypes from 'prop-types';
+import React, {memo, useMemo} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import Avatar from './Avatar';
-import Tooltip from './Tooltip';
-import Text from './Text';
-import themeColors from '../styles/themes/default';
-import * as StyleUtils from '../styles/StyleUtils';
-import CONST from '../CONST';
-import variables from '../styles/variables';
import avatarPropTypes from './avatarPropTypes';
+import Text from './Text';
+import Tooltip from './Tooltip';
import UserDetailsTooltip from './UserDetailsTooltip';
const propTypes = {
diff --git a/src/components/NewDatePicker/CalendarPicker/ArrowIcon.js b/src/components/NewDatePicker/CalendarPicker/ArrowIcon.js
index 6d5757323480..cb680a8bc43b 100644
--- a/src/components/NewDatePicker/CalendarPicker/ArrowIcon.js
+++ b/src/components/NewDatePicker/CalendarPicker/ArrowIcon.js
@@ -1,11 +1,11 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
-import * as Expensicons from '../../Icon/Expensicons';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import Icon from '../../Icon';
-import CONST from '../../../CONST';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
const propTypes = {
/** Specifies if the arrow icon should be disabled or not. */
diff --git a/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js b/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js
index 9825109fbb63..5489a9244f68 100644
--- a/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js
+++ b/src/components/NewDatePicker/CalendarPicker/YearPickerModal.js
@@ -1,14 +1,14 @@
-import React, {useEffect, useMemo, useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useEffect, useMemo, useState} from 'react';
import _ from 'underscore';
-import HeaderWithBackButton from '../../HeaderWithBackButton';
-import CONST from '../../../CONST';
-import SelectionList from '../../SelectionList';
-import Modal from '../../Modal';
-import {radioListItemPropTypes} from '../../SelectionList/selectionListPropTypes';
-import useLocalize from '../../../hooks/useLocalize';
-import ScreenWrapper from '../../ScreenWrapper';
-import styles from '../../../styles/styles';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Modal from '@components/Modal';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import {radioListItemPropTypes} from '@components/SelectionList/selectionListPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether the modal is visible */
diff --git a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js
index 7a3c55305a33..a3497654feec 100644
--- a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js
+++ b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js
@@ -1,4 +1,4 @@
-import {getDaysInMonth, startOfMonth, getDay, addDays, format} from 'date-fns';
+import {addDays, format, getDay, getDaysInMonth, startOfMonth} from 'date-fns';
/**
* Generates a matrix representation of a month's calendar given the year and month.
diff --git a/src/components/NewDatePicker/CalendarPicker/index.js b/src/components/NewDatePicker/CalendarPicker/index.js
index d03c36997845..0300b4bf476f 100644
--- a/src/components/NewDatePicker/CalendarPicker/index.js
+++ b/src/components/NewDatePicker/CalendarPicker/index.js
@@ -1,20 +1,20 @@
-import _ from 'underscore';
-import React from 'react';
-import {View} from 'react-native';
+import Str from 'expensify-common/lib/str';
import moment from 'moment';
import PropTypes from 'prop-types';
-import Str from 'expensify-common/lib/str';
-import Text from '../../Text';
-import YearPickerModal from './YearPickerModal';
+import React from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import ArrowIcon from './ArrowIcon';
-import styles from '../../../styles/styles';
import generateMonthMatrix from './generateMonthMatrix';
-import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
-import CONST from '../../../CONST';
-import getButtonState from '../../../libs/getButtonState';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import PressableWithFeedback from '../../Pressable/PressableWithFeedback';
-import PressableWithoutFeedback from '../../Pressable/PressableWithoutFeedback';
+import YearPickerModal from './YearPickerModal';
const propTypes = {
/** An initial value of date string */
diff --git a/src/components/NewDatePicker/index.js b/src/components/NewDatePicker/index.js
index 3201388790c9..30e15ac43bfc 100644
--- a/src/components/NewDatePicker/index.js
+++ b/src/components/NewDatePicker/index.js
@@ -1,16 +1,16 @@
-import React, {useEffect, useState} from 'react';
-import {View} from 'react-native';
+import _ from 'lodash';
import moment from 'moment';
import PropTypes from 'prop-types';
-import _ from 'lodash';
-import TextInput from '../TextInput';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import * as Expensicons from '../Icon/Expensicons';
-import {defaultProps as defaultBaseTextInputPropTypes, propTypes as baseTextInputPropTypes} from '../TextInput/baseTextInputPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
+import React, {useEffect, useState} from 'react';
+import {View} from 'react-native';
+import InputWrapper from '@components/Form/InputWrapper';
+import * as Expensicons from '@components/Icon/Expensicons';
+import TextInput from '@components/TextInput';
+import {propTypes as baseTextInputPropTypes, defaultProps as defaultBaseTextInputPropTypes} from '@components/TextInput/baseTextInputPropTypes';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import CalendarPicker from './CalendarPicker';
-import InputWrapper from '../Form/InputWrapper';
const propTypes = {
/**
diff --git a/src/components/OfflineIndicator.js b/src/components/OfflineIndicator.js
index 43cd374421ea..f120fe535834 100644
--- a/src/components/OfflineIndicator.js
+++ b/src/components/OfflineIndicator.js
@@ -1,16 +1,16 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import {withNetwork} from './OnyxProvider';
-import networkPropTypes from './networkPropTypes';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
-import variables from '../styles/variables';
+import networkPropTypes from './networkPropTypes';
+import {withNetwork} from './OnyxProvider';
import Text from './Text';
-import styles from '../styles/styles';
-import compose from '../libs/compose';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import * as StyleUtils from '../styles/StyleUtils';
import withWindowDimensions from './withWindowDimensions';
const propTypes = {
diff --git a/src/components/OfflineWithFeedback.js b/src/components/OfflineWithFeedback.js
index 643e7b2f4a2f..ba893aeb2fe4 100644
--- a/src/components/OfflineWithFeedback.js
+++ b/src/components/OfflineWithFeedback.js
@@ -1,19 +1,14 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import CONST from '../CONST';
-import stylePropTypes from '../styles/stylePropTypes';
-import styles from '../styles/styles';
-import Tooltip from './Tooltip';
-import Icon from './Icon';
-import * as Expensicons from './Icon/Expensicons';
-import * as StyleUtils from '../styles/StyleUtils';
-import DotIndicatorMessage from './DotIndicatorMessage';
-import shouldRenderOffscreen from '../libs/shouldRenderOffscreen';
-import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
-import useLocalize from '../hooks/useLocalize';
-import useNetwork from '../hooks/useNetwork';
+import _ from 'underscore';
+import useNetwork from '@hooks/useNetwork';
+import shouldRenderOffscreen from '@libs/shouldRenderOffscreen';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
+import MessagesRow from './MessagesRow';
/**
* This component should be used when we are using the offline pattern B (offline with feedback).
@@ -97,7 +92,6 @@ function applyStrikeThrough(children) {
}
function OfflineWithFeedback(props) {
- const {translate} = useLocalize();
const {isOffline} = useNetwork();
const hasErrors = !_.isEmpty(props.errors);
@@ -128,25 +122,13 @@ function OfflineWithFeedback(props) {
)}
{props.shouldShowErrorMessages && hasErrorMessages && (
-
-
- {props.canDismissError && (
-
-
-
-
-
- )}
-
+
)}
);
diff --git a/src/components/Onfido/BaseOnfidoWeb.js b/src/components/Onfido/BaseOnfidoWeb.js
index 394996331d5e..5c0f83902e55 100644
--- a/src/components/Onfido/BaseOnfidoWeb.js
+++ b/src/components/Onfido/BaseOnfidoWeb.js
@@ -1,16 +1,16 @@
-import _ from 'underscore';
-import './index.css';
import lodashGet from 'lodash/get';
-import React, {useEffect, forwardRef} from 'react';
import * as OnfidoSDK from 'onfido-sdk-ui';
+import React, {forwardRef, useEffect} from 'react';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import Log from '@libs/Log';
+import fontFamily from '@styles/fontFamily';
+import fontWeightBold from '@styles/fontWeight/bold';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import './index.css';
import onfidoPropTypes from './onfidoPropTypes';
-import CONST from '../../CONST';
-import variables from '../../styles/variables';
-import themeColors from '../../styles/themes/default';
-import fontWeightBold from '../../styles/fontWeight/bold';
-import fontFamily from '../../styles/fontFamily';
-import Log from '../../libs/Log';
-import useLocalize from '../../hooks/useLocalize';
function initializeOnfido({sdkToken, onSuccess, onError, onUserExit, preferredLocale, translate}) {
OnfidoSDK.init({
diff --git a/src/components/Onfido/index.native.js b/src/components/Onfido/index.native.js
index 424e370b5fe6..ed0578187d3c 100644
--- a/src/components/Onfido/index.native.js
+++ b/src/components/Onfido/index.native.js
@@ -1,13 +1,13 @@
-import _ from 'underscore';
+import {OnfidoCaptureType, OnfidoCountryCode, OnfidoDocumentType, Onfido as OnfidoSDK} from '@onfido/react-native-sdk';
import lodashGet from 'lodash/get';
import React, {useEffect} from 'react';
import {Alert, Linking} from 'react-native';
-import {Onfido as OnfidoSDK, OnfidoCaptureType, OnfidoDocumentType, OnfidoCountryCode} from '@onfido/react-native-sdk';
+import _ from 'underscore';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import useLocalize from '@hooks/useLocalize';
+import Log from '@libs/Log';
+import CONST from '@src/CONST';
import onfidoPropTypes from './onfidoPropTypes';
-import CONST from '../../CONST';
-import Log from '../../libs/Log';
-import FullscreenLoadingIndicator from '../FullscreenLoadingIndicator';
-import useLocalize from '../../hooks/useLocalize';
function Onfido({sdkToken, onUserExit, onSuccess, onError}) {
const {translate} = useLocalize();
diff --git a/src/components/Onfido/index.website.js b/src/components/Onfido/index.website.js
index 23e59fb1e08f..12ad1edd8fb9 100644
--- a/src/components/Onfido/index.website.js
+++ b/src/components/Onfido/index.website.js
@@ -1,5 +1,5 @@
-import React, {useEffect, useRef} from 'react';
import lodashGet from 'lodash/get';
+import React, {useEffect, useRef} from 'react';
import BaseOnfidoWeb from './BaseOnfidoWeb';
import onfidoPropTypes from './onfidoPropTypes';
diff --git a/src/components/OnyxProvider.tsx b/src/components/OnyxProvider.tsx
index 8682e832debc..1009a74ef1f7 100644
--- a/src/components/OnyxProvider.tsx
+++ b/src/components/OnyxProvider.tsx
@@ -1,7 +1,7 @@
import React from 'react';
-import ONYXKEYS from '../ONYXKEYS';
-import createOnyxContext from './createOnyxContext';
+import ONYXKEYS from '@src/ONYXKEYS';
import ComposeProviders from './ComposeProviders';
+import createOnyxContext from './createOnyxContext';
// Set up any providers for individual keys. This should only be used in cases where many components will subscribe to
// the same key (e.g. FlatList renderItem components)
diff --git a/src/components/OpacityView.js b/src/components/OpacityView.js
index daef93cdc09b..ebd261916e65 100644
--- a/src/components/OpacityView.js
+++ b/src/components/OpacityView.js
@@ -1,9 +1,9 @@
+import PropTypes from 'prop-types';
import React from 'react';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
-import PropTypes from 'prop-types';
-import variables from '../styles/variables';
-import * as StyleUtils from '../styles/StyleUtils';
-import shouldRenderOffscreen from '../libs/shouldRenderOffscreen';
+import shouldRenderOffscreen from '@libs/shouldRenderOffscreen';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
const propTypes = {
/**
diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js
index e3ea3acfc2ee..4939c5bac431 100644
--- a/src/components/OptionRow.js
+++ b/src/components/OptionRow.js
@@ -1,27 +1,27 @@
-import _ from 'underscore';
import lodashGet from 'lodash/get';
-import React, {useState, useEffect, useRef} from 'react';
import PropTypes from 'prop-types';
-import {View, StyleSheet, InteractionManager} from 'react-native';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import optionPropTypes from './optionPropTypes';
+import React, {useEffect, useRef, useState} from 'react';
+import {InteractionManager, StyleSheet, View} from 'react-native';
+import _ from 'underscore';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import Button from './Button';
+import DisplayNames from './DisplayNames';
+import Hoverable from './Hoverable';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
-import Button from './Button';
import MultipleAvatars from './MultipleAvatars';
-import Hoverable from './Hoverable';
-import DisplayNames from './DisplayNames';
-import themeColors from '../styles/themes/default';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import Text from './Text';
-import SelectCircle from './SelectCircle';
-import SubscriptAvatar from './SubscriptAvatar';
import OfflineWithFeedback from './OfflineWithFeedback';
-import CONST from '../CONST';
-import * as ReportUtils from '../libs/ReportUtils';
+import optionPropTypes from './optionPropTypes';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
+import SelectCircle from './SelectCircle';
+import SubscriptAvatar from './SubscriptAvatar';
+import Text from './Text';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** Style for hovered state */
diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js
index 91fd77dbea30..c7d378cde6e3 100644
--- a/src/components/OptionsList/BaseOptionsList.js
+++ b/src/components/OptionsList/BaseOptionsList.js
@@ -1,15 +1,15 @@
-import _ from 'underscore';
-import React, {useRef, useEffect, forwardRef, memo} from 'react';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
-import OptionRow from '../OptionRow';
-import SectionList from '../SectionList';
-import Text from '../Text';
-import {propTypes as optionsListPropTypes, defaultProps as optionsListDefaultProps} from './optionsListPropTypes';
-import OptionsListSkeletonView from '../OptionsListSkeletonView';
-import usePrevious from '../../hooks/usePrevious';
+import React, {forwardRef, memo, useEffect, useRef} from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import OptionRow from '@components/OptionRow';
+import OptionsListSkeletonView from '@components/OptionsListSkeletonView';
+import SectionList from '@components/SectionList';
+import Text from '@components/Text';
+import usePrevious from '@hooks/usePrevious';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import {defaultProps as optionsListDefaultProps, propTypes as optionsListPropTypes} from './optionsListPropTypes';
const propTypes = {
/** Determines whether the keyboard gets dismissed in response to a drag */
diff --git a/src/components/OptionsList/index.js b/src/components/OptionsList/index.js
index 2164b479df94..36b8e7fccf12 100644
--- a/src/components/OptionsList/index.js
+++ b/src/components/OptionsList/index.js
@@ -1,10 +1,10 @@
-import React, {forwardRef, useEffect, useRef, useCallback} from 'react';
+import React, {forwardRef, useCallback, useEffect, useRef} from 'react';
import {Keyboard} from 'react-native';
import _ from 'underscore';
+import withWindowDimensions from '@components/withWindowDimensions';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import BaseOptionsList from './BaseOptionsList';
-import withWindowDimensions from '../withWindowDimensions';
-import {propTypes, defaultProps} from './optionsListPropTypes';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
+import {defaultProps, propTypes} from './optionsListPropTypes';
function OptionsList(props) {
const isScreenTouched = useRef(false);
@@ -54,12 +54,14 @@ OptionsList.displayName = 'OptionsList';
OptionsList.propTypes = propTypes;
OptionsList.defaultProps = defaultProps;
-export default withWindowDimensions(
- forwardRef((props, ref) => (
-
- )),
-);
+const OptionsListWithRef = forwardRef((props, ref) => (
+
+));
+
+OptionsListWithRef.displayName = 'OptionsListWithRef';
+
+export default withWindowDimensions(OptionsListWithRef);
diff --git a/src/components/OptionsList/index.native.js b/src/components/OptionsList/index.native.js
index 7701096fde8f..ab2db4f20967 100644
--- a/src/components/OptionsList/index.native.js
+++ b/src/components/OptionsList/index.native.js
@@ -1,7 +1,7 @@
import React, {forwardRef} from 'react';
import {Keyboard} from 'react-native';
import BaseOptionsList from './BaseOptionsList';
-import {propTypes, defaultProps} from './optionsListPropTypes';
+import {defaultProps, propTypes} from './optionsListPropTypes';
const OptionsList = forwardRef((props, ref) => (
(
+const BasePickerWithRef = React.forwardRef((props, ref) => (
(
key={props.inputID}
/>
));
+
+BasePickerWithRef.displayName = 'BasePickerWithRef';
+
+export default BasePickerWithRef;
diff --git a/src/components/Picker/index.js b/src/components/Picker/index.js
index d0a6a4911880..8e49a42e8932 100644
--- a/src/components/Picker/index.js
+++ b/src/components/Picker/index.js
@@ -13,7 +13,7 @@ const additionalPickerEvents = (onMouseDown, onChange) => ({
},
});
-export default forwardRef((props, ref) => (
+const BasePickerWithRef = forwardRef((props, ref) => (
(
additionalPickerEvents={additionalPickerEvents}
/>
));
+
+BasePickerWithRef.displayName = 'BasePickerWithRef';
+
+export default BasePickerWithRef;
diff --git a/src/components/Picker/index.native.js b/src/components/Picker/index.native.js
index 4032e79b6d17..f441609fd4d0 100644
--- a/src/components/Picker/index.native.js
+++ b/src/components/Picker/index.native.js
@@ -1,10 +1,14 @@
import React, {forwardRef} from 'react';
import BasePicker from './BasePicker';
-export default forwardRef((props, ref) => (
+const BasePickerWithRef = forwardRef((props, ref) => (
));
+
+BasePickerWithRef.displayName = 'BasePickerWithRef';
+
+export default BasePickerWithRef;
diff --git a/src/components/PinButton.js b/src/components/PinButton.js
index 84ad6e22f50b..3c170fc94b8b 100644
--- a/src/components/PinButton.js
+++ b/src/components/PinButton.js
@@ -1,15 +1,15 @@
import React from 'react';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as Report from '@userActions/Report';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
import Icon from './Icon';
-import Tooltip from './Tooltip';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import reportPropTypes from '../pages/reportPropTypes';
-import * as Report from '../libs/actions/Report';
import * as Expensicons from './Icon/Expensicons';
-import * as Session from '../libs/actions/Session';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
-import CONST from '../CONST';
+import Tooltip from './Tooltip';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** Report to pin */
diff --git a/src/components/PlaidLink/index.js b/src/components/PlaidLink/index.js
index 319d13923996..790206f34ce7 100644
--- a/src/components/PlaidLink/index.js
+++ b/src/components/PlaidLink/index.js
@@ -1,7 +1,7 @@
import {useCallback, useEffect, useState} from 'react';
import {usePlaidLink} from 'react-plaid-link';
-import {plaidLinkPropTypes, plaidLinkDefaultProps} from './plaidLinkPropTypes';
-import Log from '../../libs/Log';
+import Log from '@libs/Log';
+import {plaidLinkDefaultProps, plaidLinkPropTypes} from './plaidLinkPropTypes';
function PlaidLink(props) {
const [isPlaidLoaded, setIsPlaidLoaded] = useState(false);
diff --git a/src/components/PlaidLink/index.native.js b/src/components/PlaidLink/index.native.js
index 48cd41e283c3..7d995d03926b 100644
--- a/src/components/PlaidLink/index.native.js
+++ b/src/components/PlaidLink/index.native.js
@@ -1,7 +1,8 @@
import {useEffect} from 'react';
-import {openLink, useDeepLinkRedirector, usePlaidEmitter} from 'react-native-plaid-link-sdk';
-import Log from '../../libs/Log';
-import {plaidLinkPropTypes, plaidLinkDefaultProps} from './plaidLinkPropTypes';
+import {dismissLink, openLink, useDeepLinkRedirector, usePlaidEmitter} from 'react-native-plaid-link-sdk';
+import Log from '@libs/Log';
+import CONST from '@src/CONST';
+import {plaidLinkDefaultProps, plaidLinkPropTypes} from './plaidLinkPropTypes';
function PlaidLink(props) {
useDeepLinkRedirector();
@@ -10,6 +11,7 @@ function PlaidLink(props) {
props.onEvent(event.eventName, event.metadata);
});
useEffect(() => {
+ props.onEvent(CONST.BANK_ACCOUNT.PLAID.EVENTS_NAME.OPEN, {});
openLink({
tokenConfig: {
token: props.token,
@@ -23,6 +25,10 @@ function PlaidLink(props) {
},
});
+ return () => {
+ dismissLink();
+ };
+
// We generally do not need to include the token as a dependency here as it is only provided once via props and should not change
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
diff --git a/src/components/Popover/index.js b/src/components/Popover/index.js
index 174570d5ed7f..b8889e806629 100644
--- a/src/components/Popover/index.js
+++ b/src/components/Popover/index.js
@@ -1,11 +1,11 @@
import React, {useRef} from 'react';
import {createPortal} from 'react-dom';
-import {propTypes, defaultProps} from './popoverPropTypes';
-import CONST from '../../CONST';
-import Modal from '../Modal';
-import withWindowDimensions from '../withWindowDimensions';
-import PopoverWithoutOverlay from '../PopoverWithoutOverlay';
-import {PopoverContext} from '../PopoverProvider';
+import Modal from '@components/Modal';
+import {PopoverContext} from '@components/PopoverProvider';
+import PopoverWithoutOverlay from '@components/PopoverWithoutOverlay';
+import withWindowDimensions from '@components/withWindowDimensions';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes} from './popoverPropTypes';
/*
* This is a convenience wrapper around the Modal component for a responsive Popover.
diff --git a/src/components/Popover/index.native.js b/src/components/Popover/index.native.js
index b4ca194e7483..c8d37c2ad61c 100644
--- a/src/components/Popover/index.native.js
+++ b/src/components/Popover/index.native.js
@@ -1,9 +1,9 @@
-import _ from 'underscore';
import React from 'react';
-import {propTypes as popoverPropTypes, defaultProps} from './popoverPropTypes';
-import CONST from '../../CONST';
-import Modal from '../Modal';
-import {windowDimensionsPropTypes} from '../withWindowDimensions';
+import _ from 'underscore';
+import Modal from '@components/Modal';
+import {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes as popoverPropTypes} from './popoverPropTypes';
const propTypes = {
..._.omit(popoverPropTypes, _.keys(windowDimensionsPropTypes)),
diff --git a/src/components/Popover/popoverPropTypes.js b/src/components/Popover/popoverPropTypes.js
index c6d0d06501a9..c13fd8fa0b85 100644
--- a/src/components/Popover/popoverPropTypes.js
+++ b/src/components/Popover/popoverPropTypes.js
@@ -1,8 +1,8 @@
-import _ from 'underscore';
import PropTypes from 'prop-types';
-import {propTypes as modalPropTypes, defaultProps as defaultModalProps} from '../Modal/modalPropTypes';
-import refPropTypes from '../refPropTypes';
-import CONST from '../../CONST';
+import _ from 'underscore';
+import {defaultProps as defaultModalProps, propTypes as modalPropTypes} from '@components/Modal/modalPropTypes';
+import refPropTypes from '@components/refPropTypes';
+import CONST from '@src/CONST';
const propTypes = {
..._.omit(modalPropTypes, ['type', 'popoverAnchorPosition']),
diff --git a/src/components/PopoverMenu/index.js b/src/components/PopoverMenu/index.js
index c4e9587bb667..0f7aa8de94e0 100644
--- a/src/components/PopoverMenu/index.js
+++ b/src/components/PopoverMenu/index.js
@@ -1,18 +1,18 @@
-import _ from 'underscore';
-import React, {useRef} from 'react';
import PropTypes from 'prop-types';
+import React, {useRef} from 'react';
import {View} from 'react-native';
-import PopoverWithMeasuredContent from '../PopoverWithMeasuredContent';
-import styles from '../../styles/styles';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
-import MenuItem from '../MenuItem';
-import {propTypes as createMenuPropTypes, defaultProps as createMenuDefaultProps} from './popoverMenuPropTypes';
-import refPropTypes from '../refPropTypes';
-import Text from '../Text';
-import CONST from '../../CONST';
-import useArrowKeyFocusManager from '../../hooks/useArrowKeyFocusManager';
-import useKeyboardShortcut from '../../hooks/useKeyboardShortcut';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
+import _ from 'underscore';
+import MenuItem from '@components/MenuItem';
+import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent';
+import refPropTypes from '@components/refPropTypes';
+import Text from '@components/Text';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import {defaultProps as createMenuDefaultProps, propTypes as createMenuPropTypes} from './popoverMenuPropTypes';
const propTypes = {
...createMenuPropTypes,
diff --git a/src/components/PopoverMenu/popoverMenuPropTypes.js b/src/components/PopoverMenu/popoverMenuPropTypes.js
index 7d95c6a860bc..ae7a385a5297 100644
--- a/src/components/PopoverMenu/popoverMenuPropTypes.js
+++ b/src/components/PopoverMenu/popoverMenuPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
const propTypes = {
/** Callback method fired when the user requests to close the modal */
diff --git a/src/components/PopoverProvider/index.js b/src/components/PopoverProvider/index.js
index 86f09579a758..3e245faceeef 100644
--- a/src/components/PopoverProvider/index.js
+++ b/src/components/PopoverProvider/index.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
const propTypes = {
children: PropTypes.node.isRequired,
diff --git a/src/components/PopoverProvider/index.native.js b/src/components/PopoverProvider/index.native.js
index e4da13752b6d..400b42ddea20 100644
--- a/src/components/PopoverProvider/index.native.js
+++ b/src/components/PopoverProvider/index.native.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
const propTypes = {
children: PropTypes.node.isRequired,
diff --git a/src/components/PopoverWithMeasuredContent.js b/src/components/PopoverWithMeasuredContent.js
index 6b71b4a59055..04eacfa88ec8 100644
--- a/src/components/PopoverWithMeasuredContent.js
+++ b/src/components/PopoverWithMeasuredContent.js
@@ -1,14 +1,14 @@
-import _ from 'underscore';
-import React, {useState, useMemo} from 'react';
import PropTypes from 'prop-types';
+import React, {useMemo, useState} from 'react';
import {View} from 'react-native';
+import _ from 'underscore';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import {computeHorizontalShift, computeVerticalShift} from '@styles/getPopoverWithMeasuredContentStyles';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import Popover from './Popover';
-import {propTypes as popoverPropTypes, defaultProps as defaultPopoverProps} from './Popover/popoverPropTypes';
-import useWindowDimensions from '../hooks/useWindowDimensions';
+import {defaultProps as defaultPopoverProps, propTypes as popoverPropTypes} from './Popover/popoverPropTypes';
import {windowDimensionsPropTypes} from './withWindowDimensions';
-import CONST from '../CONST';
-import styles from '../styles/styles';
-import {computeHorizontalShift, computeVerticalShift} from '../styles/getPopoverWithMeasuredContentStyles';
const propTypes = {
// All popover props except:
diff --git a/src/components/PopoverWithoutOverlay/index.js b/src/components/PopoverWithoutOverlay/index.js
index 2036807e0df0..43156cd11827 100644
--- a/src/components/PopoverWithoutOverlay/index.js
+++ b/src/components/PopoverWithoutOverlay/index.js
@@ -1,13 +1,13 @@
import React from 'react';
import {View} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
-import {PopoverContext} from '../PopoverProvider';
-import * as Modal from '../../libs/actions/Modal';
-import {propTypes, defaultProps} from '../Popover/popoverPropTypes';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
-import getModalStyles from '../../styles/getModalStyles';
-import withWindowDimensions from '../withWindowDimensions';
+import {defaultProps, propTypes} from '@components/Popover/popoverPropTypes';
+import {PopoverContext} from '@components/PopoverProvider';
+import withWindowDimensions from '@components/withWindowDimensions';
+import getModalStyles from '@styles/getModalStyles';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as Modal from '@userActions/Modal';
function Popover(props) {
const {onOpen, close} = React.useContext(PopoverContext);
diff --git a/src/components/Pressable/GenericPressable/BaseGenericPressable.js b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
index 24d81f59f4f8..a3ce55003cdd 100644
--- a/src/components/Pressable/GenericPressable/BaseGenericPressable.js
+++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
@@ -1,15 +1,15 @@
-import React, {useCallback, useEffect, useMemo, forwardRef} from 'react';
+import React, {forwardRef, useCallback, useEffect, useMemo} from 'react';
// eslint-disable-next-line no-restricted-imports
import {Pressable} from 'react-native';
import _ from 'underscore';
-import Accessibility from '../../../libs/Accessibility';
-import HapticFeedback from '../../../libs/HapticFeedback';
-import KeyboardShortcut from '../../../libs/KeyboardShortcut';
-import styles from '../../../styles/styles';
+import useSingleExecution from '@hooks/useSingleExecution';
+import Accessibility from '@libs/Accessibility';
+import HapticFeedback from '@libs/HapticFeedback';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
import genericPressablePropTypes from './PropTypes';
-import CONST from '../../../CONST';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import useSingleExecution from '../../../hooks/useSingleExecution';
/**
* Returns the cursor style based on the state of Pressable
diff --git a/src/components/Pressable/GenericPressable/PropTypes.js b/src/components/Pressable/GenericPressable/PropTypes.js
index 3933b31d2d47..870c63301239 100644
--- a/src/components/Pressable/GenericPressable/PropTypes.js
+++ b/src/components/Pressable/GenericPressable/PropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import stylePropType from '../../../styles/stylePropTypes';
-import CONST from '../../../CONST';
+import stylePropType from '@styles/stylePropTypes';
+import CONST from '@src/CONST';
const stylePropTypeWithFunction = PropTypes.oneOfType([stylePropType, PropTypes.func]);
diff --git a/src/components/Pressable/GenericPressable/index.js b/src/components/Pressable/GenericPressable/index.js
index 774ac3ac5092..8247d0c35670 100644
--- a/src/components/Pressable/GenericPressable/index.js
+++ b/src/components/Pressable/GenericPressable/index.js
@@ -21,5 +21,6 @@ const WebGenericPressable = forwardRef((props, ref) => (
WebGenericPressable.propTypes = GenericPressablePropTypes.pressablePropTypes;
WebGenericPressable.defaultProps = GenericPressablePropTypes.defaultProps;
+WebGenericPressable.displayName = 'WebGenericPressable';
export default WebGenericPressable;
diff --git a/src/components/Pressable/GenericPressable/index.native.js b/src/components/Pressable/GenericPressable/index.native.js
index 3de74eda35de..14a2c2bcbf82 100644
--- a/src/components/Pressable/GenericPressable/index.native.js
+++ b/src/components/Pressable/GenericPressable/index.native.js
@@ -15,5 +15,6 @@ const NativeGenericPressable = forwardRef((props, ref) => (
NativeGenericPressable.propTypes = GenericPressablePropTypes.pressablePropTypes;
NativeGenericPressable.defaultProps = GenericPressablePropTypes.defaultProps;
+NativeGenericPressable.displayName = 'WebGenericPressable';
export default NativeGenericPressable;
diff --git a/src/components/Pressable/PressableWithDelayToggle.js b/src/components/Pressable/PressableWithDelayToggle.js
index b55770a63196..7113afff8bdc 100644
--- a/src/components/Pressable/PressableWithDelayToggle.js
+++ b/src/components/Pressable/PressableWithDelayToggle.js
@@ -1,16 +1,16 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import * as Expensicons from '../Icon/Expensicons';
-import Icon from '../Icon';
-import Tooltip from '../Tooltip';
-import Text from '../Text';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
-import getButtonState from '../../libs/getButtonState';
-import * as StyleUtils from '../../styles/StyleUtils';
+import React from 'react';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import refPropTypes from '@components/refPropTypes';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import useThrottledButtonState from '@hooks/useThrottledButtonState';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
import PressableWithoutFeedback from './PressableWithoutFeedback';
-import useThrottledButtonState from '../../hooks/useThrottledButtonState';
-import refPropTypes from '../refPropTypes';
const propTypes = {
/** Ref passed to the component by React.forwardRef (do not pass from parent) */
@@ -141,10 +141,14 @@ function PressableWithDelayToggle(props) {
PressableWithDelayToggle.propTypes = propTypes;
PressableWithDelayToggle.defaultProps = defaultProps;
-export default React.forwardRef((props, ref) => (
+const PressableWithDelayToggleWithRef = React.forwardRef((props, ref) => (
));
+
+PressableWithDelayToggleWithRef.displayName = 'PressableWithDelayToggleWithRef';
+
+export default PressableWithDelayToggleWithRef;
diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js
index 07601ed35789..ad29204bb018 100644
--- a/src/components/Pressable/PressableWithFeedback.js
+++ b/src/components/Pressable/PressableWithFeedback.js
@@ -1,10 +1,10 @@
+import propTypes from 'prop-types';
import React, {forwardRef, useState} from 'react';
import _ from 'underscore';
-import propTypes from 'prop-types';
+import OpacityView from '@components/OpacityView';
+import variables from '@styles/variables';
import GenericPressable from './GenericPressable';
import GenericPressablePropTypes from './GenericPressable/PropTypes';
-import OpacityView from '../OpacityView';
-import variables from '../../styles/variables';
const omittedProps = ['wrapperStyle', 'needsOffscreenAlphaCompositing'];
diff --git a/src/components/Pressable/PressableWithoutFocus.js b/src/components/Pressable/PressableWithoutFocus.js
index 5e56c71f09da..641e695b1013 100644
--- a/src/components/Pressable/PressableWithoutFocus.js
+++ b/src/components/Pressable/PressableWithoutFocus.js
@@ -1,9 +1,9 @@
+import PropTypes from 'prop-types';
import React from 'react';
import _ from 'underscore';
-import PropTypes from 'prop-types';
+import StylePropType from '@styles/stylePropTypes';
import GenericPressable from './GenericPressable';
import genericPressablePropTypes from './GenericPressable/PropTypes';
-import StylePropType from '../../styles/stylePropTypes';
const propTypes = {
/** Element that should be clickable */
diff --git a/src/components/PressableWithSecondaryInteraction/index.js b/src/components/PressableWithSecondaryInteraction/index.js
index d84a3f282e97..ec6127dbf1fa 100644
--- a/src/components/PressableWithSecondaryInteraction/index.js
+++ b/src/components/PressableWithSecondaryInteraction/index.js
@@ -1,9 +1,9 @@
-import _ from 'underscore';
import React, {forwardRef, useEffect, useRef} from 'react';
-import styles from '../../styles/styles';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import * as StyleUtils from '../../styles/StyleUtils';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
+import _ from 'underscore';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes';
/**
@@ -117,10 +117,14 @@ PressableWithSecondaryInteraction.propTypes = pressableWithSecondaryInteractionP
PressableWithSecondaryInteraction.defaultProps = pressableWithSecondaryInteractionPropTypes.defaultProps;
PressableWithSecondaryInteraction.displayName = 'PressableWithSecondaryInteraction';
-export default forwardRef((props, ref) => (
+const PressableWithSecondaryInteractionWithRef = forwardRef((props, ref) => (
));
+
+PressableWithSecondaryInteractionWithRef.displayName = 'PressableWithSecondaryInteractionWithRef';
+
+export default PressableWithSecondaryInteractionWithRef;
diff --git a/src/components/PressableWithSecondaryInteraction/index.native.js b/src/components/PressableWithSecondaryInteraction/index.native.js
index 0ca668bb4234..039801bee3f2 100644
--- a/src/components/PressableWithSecondaryInteraction/index.native.js
+++ b/src/components/PressableWithSecondaryInteraction/index.native.js
@@ -1,8 +1,8 @@
-import _ from 'underscore';
import React, {forwardRef} from 'react';
+import _ from 'underscore';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
import * as pressableWithSecondaryInteractionPropTypes from './pressableWithSecondaryInteractionPropTypes';
-import Text from '../Text';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
/**
* This is a special Pressable that calls onSecondaryInteraction when LongPressed.
@@ -38,10 +38,14 @@ PressableWithSecondaryInteraction.propTypes = pressableWithSecondaryInteractionP
PressableWithSecondaryInteraction.defaultProps = pressableWithSecondaryInteractionPropTypes.defaultProps;
PressableWithSecondaryInteraction.displayName = 'PressableWithSecondaryInteraction';
-export default forwardRef((props, ref) => (
+const PressableWithSecondaryInteractionWithRef = forwardRef((props, ref) => (
));
+
+PressableWithSecondaryInteractionWithRef.displayName = 'PressableWithSecondaryInteractionWithRef';
+
+export default PressableWithSecondaryInteractionWithRef;
diff --git a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js
index 0a4f7949643a..8e2fb5141091 100644
--- a/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js
+++ b/src/components/PressableWithSecondaryInteraction/pressableWithSecondaryInteractionPropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import refPropTypes from '../refPropTypes';
-import stylePropTypes from '../../styles/stylePropTypes';
+import refPropTypes from '@components/refPropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
const propTypes = {
/** The function that should be called when this pressable is pressed */
diff --git a/src/components/QRCode/index.tsx b/src/components/QRCode/index.tsx
index bca45c02fffa..86e6ac6c7ff5 100644
--- a/src/components/QRCode/index.tsx
+++ b/src/components/QRCode/index.tsx
@@ -1,8 +1,8 @@
import React, {Ref} from 'react';
-import QRCodeLibrary from 'react-native-qrcode-svg';
import {ImageSourcePropType} from 'react-native';
-import defaultTheme from '../../styles/themes/default';
-import CONST from '../../CONST';
+import QRCodeLibrary from 'react-native-qrcode-svg';
+import defaultTheme from '@styles/themes/default';
+import CONST from '@src/CONST';
type LogoRatio = typeof CONST.QR.DEFAULT_LOGO_SIZE_RATIO | typeof CONST.QR.EXPENSIFY_LOGO_SIZE_RATIO;
diff --git a/src/components/QRShare/QRShareWithDownload/index.js b/src/components/QRShare/QRShareWithDownload/index.js
index b16f22dc6483..688ec15040ac 100644
--- a/src/components/QRShare/QRShareWithDownload/index.js
+++ b/src/components/QRShare/QRShareWithDownload/index.js
@@ -1,9 +1,9 @@
import React, {Component} from 'react';
-import fileDownload from '../../../libs/fileDownload';
+import {withNetwork} from '@components/OnyxProvider';
+import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
+import {qrShareDefaultProps, qrSharePropTypes} from '@components/QRShare/propTypes';
+import fileDownload from '@libs/fileDownload';
import QRShare from '..';
-import {qrShareDefaultProps, qrSharePropTypes} from '../propTypes';
-import getQrCodeFileName from '../getQrCodeDownloadFileName';
-import {withNetwork} from '../../OnyxProvider';
class QRShareWithDownload extends Component {
qrShareRef = React.createRef();
diff --git a/src/components/QRShare/QRShareWithDownload/index.native.js b/src/components/QRShare/QRShareWithDownload/index.native.js
index 66fe7a6762d0..bf67b0955812 100644
--- a/src/components/QRShare/QRShareWithDownload/index.native.js
+++ b/src/components/QRShare/QRShareWithDownload/index.native.js
@@ -1,10 +1,10 @@
import React, {Component} from 'react';
import ViewShot from 'react-native-view-shot';
-import fileDownload from '../../../libs/fileDownload';
+import {withNetwork} from '@components/OnyxProvider';
+import getQrCodeFileName from '@components/QRShare/getQrCodeDownloadFileName';
+import {qrShareDefaultProps, qrSharePropTypes} from '@components/QRShare/propTypes';
+import fileDownload from '@libs/fileDownload';
import QRShare from '..';
-import {qrShareDefaultProps, qrSharePropTypes} from '../propTypes';
-import getQrCodeFileName from '../getQrCodeDownloadFileName';
-import {withNetwork} from '../../OnyxProvider';
class QRShareWithDownload extends Component {
qrCodeScreenshotRef = React.createRef();
diff --git a/src/components/QRShare/getQrCodeDownloadFileName.js b/src/components/QRShare/getQrCodeDownloadFileName.js
index cc3b38d42348..c1e73a1794fb 100644
--- a/src/components/QRShare/getQrCodeDownloadFileName.js
+++ b/src/components/QRShare/getQrCodeDownloadFileName.js
@@ -1,4 +1,3 @@
-// eslint-disable-next-line rulesdir/display-name-property
const getQrCodeDownloadFileName = (title) => `${title}-ShareCode.png`;
export default getQrCodeDownloadFileName;
diff --git a/src/components/QRShare/index.js b/src/components/QRShare/index.js
index 837adcac8efe..7e709cad84f0 100644
--- a/src/components/QRShare/index.js
+++ b/src/components/QRShare/index.js
@@ -1,16 +1,16 @@
import React, {Component} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import defaultTheme from '../../styles/themes/default';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
-import compose from '../../libs/compose';
-import variables from '../../styles/variables';
-import ExpensifyWordmark from '../../../assets/images/expensify-wordmark.svg';
-import {qrSharePropTypes, qrShareDefaultProps} from './propTypes';
-import QRCode from '../QRCode';
+import ExpensifyWordmark from '@assets/images/expensify-wordmark.svg';
+import QRCode from '@components/QRCode';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import defaultTheme from '@styles/themes/default';
+import variables from '@styles/variables';
+import {qrShareDefaultProps, qrSharePropTypes} from './propTypes';
const propTypes = {
...qrSharePropTypes,
diff --git a/src/components/RNTextInput.js b/src/components/RNTextInput.js
index 5a790cde91d7..d308c42f4947 100644
--- a/src/components/RNTextInput.js
+++ b/src/components/RNTextInput.js
@@ -1,9 +1,9 @@
+import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'underscore';
// eslint-disable-next-line no-restricted-imports
import {TextInput} from 'react-native';
import Animated from 'react-native-reanimated';
-import PropTypes from 'prop-types';
+import _ from 'underscore';
const propTypes = {
/** A ref to forward to the text input */
@@ -38,10 +38,14 @@ RNTextInput.propTypes = propTypes;
RNTextInput.defaultProps = defaultProps;
RNTextInput.displayName = 'RNTextInput';
-export default React.forwardRef((props, ref) => (
+const RNTextInputWithRef = React.forwardRef((props, ref) => (
));
+
+RNTextInputWithRef.displayName = 'RNTextInputWithRef';
+
+export default RNTextInputWithRef;
diff --git a/src/components/RadioButton.js b/src/components/RadioButton.js
index 726afd609588..9d8e739d723c 100644
--- a/src/components/RadioButton.js
+++ b/src/components/RadioButton.js
@@ -1,11 +1,11 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
-import CONST from '../CONST';
const propTypes = {
/** Whether radioButton is checked */
diff --git a/src/components/RadioButtonWithLabel.js b/src/components/RadioButtonWithLabel.js
index 6175b29c01db..21a04bfcefef 100644
--- a/src/components/RadioButtonWithLabel.js
+++ b/src/components/RadioButtonWithLabel.js
@@ -1,12 +1,12 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../styles/styles';
-import RadioButton from './RadioButton';
-import Text from './Text';
+import styles from '@styles/styles';
import FormHelpMessage from './FormHelpMessage';
import * as Pressables from './Pressable';
+import RadioButton from './RadioButton';
+import Text from './Text';
const propTypes = {
/** Whether the radioButton is checked */
diff --git a/src/components/RadioButtons.js b/src/components/RadioButtons.tsx
similarity index 54%
rename from src/components/RadioButtons.js
rename to src/components/RadioButtons.tsx
index 455f4dad1674..23b813759ecf 100644
--- a/src/components/RadioButtons.js
+++ b/src/components/RadioButtons.tsx
@@ -1,36 +1,34 @@
import React, {useState} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
+import styles from '@styles/styles';
import RadioButtonWithLabel from './RadioButtonWithLabel';
-import styles from '../styles/styles';
-const propTypes = {
+type Choice = {
+ label: string;
+ value: string;
+};
+
+type RadioButtonsProps = {
/** List of choices to display via radio buttons */
- items: PropTypes.arrayOf(
- PropTypes.shape({
- label: PropTypes.string.isRequired,
- value: PropTypes.string.isRequired,
- }),
- ).isRequired,
+ items: Choice[];
/** Callback to fire when selecting a radio button */
- onPress: PropTypes.func.isRequired,
+ onPress: (value: string) => void;
};
-function RadioButtons(props) {
+function RadioButtons({items, onPress}: RadioButtonsProps) {
const [checkedValue, setCheckedValue] = useState('');
return (
- {_.map(props.items, (item, index) => (
+ {items.map((item) => (
{
setCheckedValue(item.value);
- return props.onPress(item.value);
+ return onPress(item.value);
}}
label={item.label}
/>
@@ -39,7 +37,6 @@ function RadioButtons(props) {
);
}
-RadioButtons.propTypes = propTypes;
RadioButtons.displayName = 'RadioButtons';
export default RadioButtons;
diff --git a/src/components/Reactions/AddReactionBubble.js b/src/components/Reactions/AddReactionBubble.js
index 8a862c7e1b96..4e12ace9cc6c 100644
--- a/src/components/Reactions/AddReactionBubble.js
+++ b/src/components/Reactions/AddReactionBubble.js
@@ -1,19 +1,19 @@
-import React, {useRef, useEffect} from 'react';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
-import Tooltip from '../Tooltip/PopoverAnchorTooltip';
-import styles from '../../styles/styles';
-import * as StyleUtils from '../../styles/StyleUtils';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import Text from '../Text';
-import getButtonState from '../../libs/getButtonState';
-import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction';
-import variables from '../../styles/variables';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import * as Session from '../../libs/actions/Session';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
-import CONST from '../../CONST';
+import React, {useEffect, useRef} from 'react';
+import {View} from 'react-native';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
+import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether it is for context menu so we can modify its style */
diff --git a/src/components/Reactions/EmojiReactionBubble.js b/src/components/Reactions/EmojiReactionBubble.js
index 818bc8f33309..a61923e49860 100644
--- a/src/components/Reactions/EmojiReactionBubble.js
+++ b/src/components/Reactions/EmojiReactionBubble.js
@@ -1,12 +1,12 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import * as StyleUtils from '../../styles/StyleUtils';
-import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
-import {withCurrentUserPersonalDetailsDefaultProps} from '../withCurrentUserPersonalDetails';
-import CONST from '../../CONST';
+import React from 'react';
+import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import Text from '@components/Text';
+import {withCurrentUserPersonalDetailsDefaultProps} from '@components/withCurrentUserPersonalDetails';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
const propTypes = {
/**
@@ -96,12 +96,14 @@ EmojiReactionBubble.propTypes = propTypes;
EmojiReactionBubble.defaultProps = defaultProps;
EmojiReactionBubble.displayName = 'EmojiReactionBubble';
-export default withWindowDimensions(
- React.forwardRef((props, ref) => (
-
- )),
-);
+const EmojiReactionBubbleWithRef = React.forwardRef((props, ref) => (
+
+));
+
+EmojiReactionBubbleWithRef.displayName = 'EmojiReactionBubbleWithRef';
+
+export default withWindowDimensions(EmojiReactionBubbleWithRef);
diff --git a/src/components/Reactions/MiniQuickEmojiReactions.js b/src/components/Reactions/MiniQuickEmojiReactions.js
index a22a2967cefe..aacadc451848 100644
--- a/src/components/Reactions/MiniQuickEmojiReactions.js
+++ b/src/components/Reactions/MiniQuickEmojiReactions.js
@@ -1,23 +1,23 @@
+import PropTypes from 'prop-types';
import React, {useRef} from 'react';
import {View} from 'react-native';
-import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import * as StyleUtils from '../../styles/StyleUtils';
-import BaseMiniContextMenuItem from '../BaseMiniContextMenuItem';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import getButtonState from '../../libs/getButtonState';
-import * as EmojiPickerAction from '../../libs/actions/EmojiPickerAction';
-import {baseQuickEmojiReactionsPropTypes, baseQuickEmojiReactionsDefaultProps} from './QuickEmojiReactions/BaseQuickEmojiReactions';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as EmojiUtils from '../../libs/EmojiUtils';
-import * as Session from '../../libs/actions/Session';
+import _ from 'underscore';
+import BaseMiniContextMenuItem from '@components/BaseMiniContextMenuItem';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import getButtonState from '@libs/getButtonState';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {baseQuickEmojiReactionsDefaultProps, baseQuickEmojiReactionsPropTypes} from './QuickEmojiReactions/BaseQuickEmojiReactions';
const propTypes = {
...baseQuickEmojiReactionsPropTypes,
diff --git a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
index b5046fbd59ce..5d8a94b19e77 100644
--- a/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
+++ b/src/components/Reactions/QuickEmojiReactions/BaseQuickEmojiReactions.js
@@ -1,17 +1,17 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import _ from 'underscore';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import EmojiReactionBubble from '../EmojiReactionBubble';
-import AddReactionBubble from '../AddReactionBubble';
-import CONST from '../../../CONST';
-import styles from '../../../styles/styles';
-import ONYXKEYS from '../../../ONYXKEYS';
-import Tooltip from '../../Tooltip';
-import * as EmojiUtils from '../../../libs/EmojiUtils';
-import EmojiReactionsPropTypes from '../EmojiReactionsPropTypes';
-import * as Session from '../../../libs/actions/Session';
+import _ from 'underscore';
+import AddReactionBubble from '@components/Reactions/AddReactionBubble';
+import EmojiReactionBubble from '@components/Reactions/EmojiReactionBubble';
+import EmojiReactionsPropTypes from '@components/Reactions/EmojiReactionsPropTypes';
+import Tooltip from '@components/Tooltip';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const baseQuickEmojiReactionsPropTypes = {
emojiReactions: EmojiReactionsPropTypes,
diff --git a/src/components/Reactions/QuickEmojiReactions/index.js b/src/components/Reactions/QuickEmojiReactions/index.js
index dd05c4f2cea3..e4399b634136 100644
--- a/src/components/Reactions/QuickEmojiReactions/index.js
+++ b/src/components/Reactions/QuickEmojiReactions/index.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import {contextMenuRef} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
+import CONST from '@src/CONST';
import BaseQuickEmojiReactions, {baseQuickEmojiReactionsPropTypes} from './BaseQuickEmojiReactions';
-import {contextMenuRef} from '../../../pages/home/report/ContextMenu/ReportActionContextMenu';
-import CONST from '../../../CONST';
const propTypes = {
...baseQuickEmojiReactionsPropTypes,
diff --git a/src/components/Reactions/QuickEmojiReactions/index.native.js b/src/components/Reactions/QuickEmojiReactions/index.native.js
index 5ad8e0097e0e..239fd7b4c8a8 100644
--- a/src/components/Reactions/QuickEmojiReactions/index.native.js
+++ b/src/components/Reactions/QuickEmojiReactions/index.native.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
import BaseQuickEmojiReactions, {baseQuickEmojiReactionsPropTypes} from './BaseQuickEmojiReactions';
-import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager';
const propTypes = {
...baseQuickEmojiReactionsPropTypes,
diff --git a/src/components/Reactions/ReactionTooltipContent.js b/src/components/Reactions/ReactionTooltipContent.js
index 8dddc106efbf..c1fdd2e61637 100644
--- a/src/components/Reactions/ReactionTooltipContent.js
+++ b/src/components/Reactions/ReactionTooltipContent.js
@@ -1,12 +1,12 @@
+import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import * as PersonalDetailsUtils from '../../libs/PersonalDetailsUtils';
-import Text from '../Text';
-import {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails';
-import withLocalize from '../withLocalize';
+import Text from '@components/Text';
+import {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize from '@components/withLocalize';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import styles from '@styles/styles';
const propTypes = {
/**
diff --git a/src/components/Reactions/ReportActionItemEmojiReactions.js b/src/components/Reactions/ReportActionItemEmojiReactions.js
index 5fdf74f877dd..8709f0c6f718 100644
--- a/src/components/Reactions/ReportActionItemEmojiReactions.js
+++ b/src/components/Reactions/ReportActionItemEmojiReactions.js
@@ -1,21 +1,21 @@
-import React, {useRef, useContext} from 'react';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import EmojiReactionBubble from './EmojiReactionBubble';
+import React, {useContext, useRef} from 'react';
+import {View} from 'react-native';
+import _ from 'underscore';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import Tooltip from '@components/Tooltip';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import {ReactionListContext} from '@pages/home/ReportScreenContext';
+import styles from '@styles/styles';
import AddReactionBubble from './AddReactionBubble';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails';
-import withLocalize from '../withLocalize';
-import compose from '../../libs/compose';
+import EmojiReactionBubble from './EmojiReactionBubble';
import EmojiReactionsPropTypes from './EmojiReactionsPropTypes';
-import Tooltip from '../Tooltip';
import ReactionTooltipContent from './ReactionTooltipContent';
-import * as EmojiUtils from '../../libs/EmojiUtils';
-import {ReactionListContext} from '../../pages/home/ReportScreenContext';
-import OfflineWithFeedback from '../OfflineWithFeedback';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
const propTypes = {
emojiReactions: EmojiReactionsPropTypes,
diff --git a/src/components/ReimbursementAccountLoadingIndicator.js b/src/components/ReimbursementAccountLoadingIndicator.js
index bd3011a74ffb..46aff91c93ea 100644
--- a/src/components/ReimbursementAccountLoadingIndicator.js
+++ b/src/components/ReimbursementAccountLoadingIndicator.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {StyleSheet, View} from 'react-native';
-import PropTypes from 'prop-types';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import FullPageOfflineBlockingView from './BlockingViews/FullPageOfflineBlockingView';
+import FullScreenLoadingIndicator from './FullscreenLoadingIndicator';
+import HeaderWithBackButton from './HeaderWithBackButton';
import Lottie from './Lottie';
import * as LottieAnimations from './LottieAnimations';
-import styles from '../styles/styles';
-import useLocalize from '../hooks/useLocalize';
-import Text from './Text';
-import HeaderWithBackButton from './HeaderWithBackButton';
import ScreenWrapper from './ScreenWrapper';
-import FullScreenLoadingIndicator from './FullscreenLoadingIndicator';
-import FullPageOfflineBlockingView from './BlockingViews/FullPageOfflineBlockingView';
+import Text from './Text';
const propTypes = {
/** Whether the user is submitting verifications data */
diff --git a/src/components/RenderHTML.js b/src/components/RenderHTML.js
index d2d4f0b58e71..feb5d25cae44 100644
--- a/src/components/RenderHTML.js
+++ b/src/components/RenderHTML.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {RenderHTMLSource} from 'react-native-render-html';
-import useWindowDimensions from '../hooks/useWindowDimensions';
+import useWindowDimensions from '@hooks/useWindowDimensions';
const propTypes = {
/** HTML string to render */
diff --git a/src/components/ReportActionItem/ChronosOOOListActions.js b/src/components/ReportActionItem/ChronosOOOListActions.js
index 61c504d122ff..f09b4880d8c6 100644
--- a/src/components/ReportActionItem/ChronosOOOListActions.js
+++ b/src/components/ReportActionItem/ChronosOOOListActions.js
@@ -1,16 +1,16 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
-import styles from '../../styles/styles';
-import Text from '../Text';
-import Button from '../Button';
-import * as Chronos from '../../libs/actions/Chronos';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import DateUtils from '../../libs/DateUtils';
-import OfflineWithFeedback from '../OfflineWithFeedback';
+import Button from '@components/Button';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import DateUtils from '@libs/DateUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import styles from '@styles/styles';
+import * as Chronos from '@userActions/Chronos';
const propTypes = {
/** The ID of the report */
diff --git a/src/components/ReportActionItem/MoneyReportView.js b/src/components/ReportActionItem/MoneyReportView.js
index 3f9b8bf53837..eb0d5891111d 100644
--- a/src/components/ReportActionItem/MoneyReportView.js
+++ b/src/components/ReportActionItem/MoneyReportView.js
@@ -1,20 +1,20 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import reportPropTypes from '../../pages/reportPropTypes';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as StyleUtils from '../../styles/StyleUtils';
-import Text from '../Text';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import variables from '../../styles/variables';
-import * as CurrencyUtils from '../../libs/CurrencyUtils';
-import useLocalize from '../../hooks/useLocalize';
-import AnimatedEmptyStateBackground from '../../pages/home/report/AnimatedEmptyStateBackground';
-import SpacerView from '../SpacerView';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import SpacerView from '@components/SpacerView';
+import Text from '@components/Text';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useLocalize from '@hooks/useLocalize';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
const propTypes = {
/** The report currently being looked at */
diff --git a/src/components/ReportActionItem/MoneyRequestAction.js b/src/components/ReportActionItem/MoneyRequestAction.js
index 136e6a753e67..4de1cc7b6889 100644
--- a/src/components/ReportActionItem/MoneyRequestAction.js
+++ b/src/components/ReportActionItem/MoneyRequestAction.js
@@ -1,28 +1,28 @@
-import _ from 'underscore';
-import React from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import {withNetwork} from '../OnyxProvider';
-import compose from '../../libs/compose';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
-import networkPropTypes from '../networkPropTypes';
-import iouReportPropTypes from '../../pages/iouReportPropTypes';
+import _ from 'underscore';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import refPropTypes from '@components/refPropTypes';
+import RenderHTML from '@components/RenderHTML';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as IOUUtils from '@libs/IOUUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import iouReportPropTypes from '@pages/iouReportPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import MoneyRequestPreview from './MoneyRequestPreview';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import styles from '../../styles/styles';
-import * as IOUUtils from '../../libs/IOUUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as Report from '../../libs/actions/Report';
-import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
-import refPropTypes from '../refPropTypes';
-import RenderHTML from '../RenderHTML';
-import * as PersonalDetailsUtils from '../../libs/PersonalDetailsUtils';
-import reportPropTypes from '../../pages/reportPropTypes';
-import useLocalize from '../../hooks/useLocalize';
const propTypes = {
/** All the data of the action */
diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js
index 43500c731728..97043fbd055d 100644
--- a/src/components/ReportActionItem/MoneyRequestPreview.js
+++ b/src/components/ReportActionItem/MoneyRequestPreview.js
@@ -1,42 +1,42 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import compose from '../../libs/compose';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import MultipleAvatars from '../MultipleAvatars';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import * as Report from '../../libs/actions/Report';
-import themeColors from '../../styles/themes/default';
-import Icon from '../Icon';
-import CONST from '../../CONST';
-import * as Expensicons from '../Icon/Expensicons';
-import Text from '../Text';
-import * as PaymentMethods from '../../libs/actions/PaymentMethods';
-import OfflineWithFeedback from '../OfflineWithFeedback';
-import walletTermsPropTypes from '../../pages/EnablePayments/walletTermsPropTypes';
-import ControlSelection from '../../libs/ControlSelection';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
-import {showContextMenuForReport} from '../ShowContextMenuContext';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
-import * as CurrencyUtils from '../../libs/CurrencyUtils';
-import * as IOUUtils from '../../libs/IOUUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as TransactionUtils from '../../libs/TransactionUtils';
-import refPropTypes from '../refPropTypes';
-import PressableWithFeedback from '../Pressable/PressableWithoutFeedback';
-import * as ReceiptUtils from '../../libs/ReceiptUtils';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MoneyRequestSkeletonView from '@components/MoneyRequestSkeletonView';
+import MultipleAvatars from '@components/MultipleAvatars';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithFeedback from '@components/Pressable/PressableWithoutFeedback';
+import refPropTypes from '@components/refPropTypes';
+import {showContextMenuForReport} from '@components/ShowContextMenuContext';
+import Text from '@components/Text';
+import transactionPropTypes from '@components/transactionPropTypes';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import compose from '@libs/compose';
+import ControlSelection from '@libs/ControlSelection';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as IOUUtils from '@libs/IOUUtils';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReceiptUtils from '@libs/ReceiptUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import walletTermsPropTypes from '@pages/EnablePayments/walletTermsPropTypes';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import ReportActionItemImages from './ReportActionItemImages';
-import transactionPropTypes from '../transactionPropTypes';
-import * as StyleUtils from '../../styles/StyleUtils';
-import variables from '../../styles/variables';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import MoneyRequestSkeletonView from '../MoneyRequestSkeletonView';
const propTypes = {
/** The active IOUReport, used for Onyx subscription */
@@ -166,6 +166,7 @@ function MoneyRequestPreview(props) {
const isDistanceRequest = TransactionUtils.isDistanceRequest(props.transaction);
const isExpensifyCardTransaction = TransactionUtils.isExpensifyCardTransaction(props.transaction);
const isSettled = ReportUtils.isSettled(props.iouReport.reportID);
+ const isDeleted = lodashGet(props.action, 'pendingAction', null) === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
// Show the merchant for IOUs and expenses only if they are custom or not related to scanning smartscan
const shouldShowMerchant =
@@ -232,6 +233,16 @@ function MoneyRequestPreview(props) {
return CurrencyUtils.convertToDisplayString(requestAmount, requestCurrency);
};
+ const getDisplayDeleteAmountText = () => {
+ const {amount, currency} = ReportUtils.getTransactionDetails(props.action.originalMessage);
+
+ if (isDistanceRequest) {
+ return CurrencyUtils.convertToDisplayString(TransactionUtils.getAmount(props.action.originalMessage), currency);
+ }
+
+ return CurrencyUtils.convertToDisplayString(amount, currency);
+ };
+
const childContainer = (
- {getDisplayAmountText()}
+ {isDeleted ? getDisplayDeleteAmountText() : getDisplayAmountText()}
{ReportUtils.isSettled(props.iouReport.reportID) && !props.isBillSplit && (
diff --git a/src/components/ReportActionItem/MoneyRequestView.js b/src/components/ReportActionItem/MoneyRequestView.js
index 19f4a5b8e103..aa1813fa6e4d 100644
--- a/src/components/ReportActionItem/MoneyRequestView.js
+++ b/src/components/ReportActionItem/MoneyRequestView.js
@@ -1,43 +1,43 @@
-import React, {useMemo} from 'react';
-import {View} from 'react-native';
-import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import lodashValues from 'lodash/values';
import PropTypes from 'prop-types';
-import reportPropTypes from '../../pages/reportPropTypes';
-import ONYXKEYS from '../../ONYXKEYS';
-import ROUTES from '../../ROUTES';
-import Permissions from '../../libs/Permissions';
-import Navigation from '../../libs/Navigation/Navigation';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails';
-import compose from '../../libs/compose';
-import MenuItemWithTopDescription from '../MenuItemWithTopDescription';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as IOU from '../../libs/actions/IOU';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
-import * as StyleUtils from '../../styles/StyleUtils';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import * as CardUtils from '../../libs/CardUtils';
-import CONST from '../../CONST';
-import * as Expensicons from '../Icon/Expensicons';
-import iouReportPropTypes from '../../pages/iouReportPropTypes';
-import * as CurrencyUtils from '../../libs/CurrencyUtils';
-import useLocalize from '../../hooks/useLocalize';
-import AnimatedEmptyStateBackground from '../../pages/home/report/AnimatedEmptyStateBackground';
-import * as ReceiptUtils from '../../libs/ReceiptUtils';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import transactionPropTypes from '../transactionPropTypes';
-import Text from '../Text';
-import Switch from '../Switch';
+import React, {useMemo} from 'react';
+import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import categoryPropTypes from '@components/categoryPropTypes';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import SpacerView from '@components/SpacerView';
+import Switch from '@components/Switch';
+import tagPropTypes from '@components/tagPropTypes';
+import Text from '@components/Text';
+import transactionPropTypes from '@components/transactionPropTypes';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as CardUtils from '@libs/CardUtils';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReceiptUtils from '@libs/ReceiptUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import AnimatedEmptyStateBackground from '@pages/home/report/AnimatedEmptyStateBackground';
+import iouReportPropTypes from '@pages/iouReportPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import ReportActionItemImage from './ReportActionItemImage';
-import * as TransactionUtils from '../../libs/TransactionUtils';
-import OfflineWithFeedback from '../OfflineWithFeedback';
-import categoryPropTypes from '../categoryPropTypes';
-import SpacerView from '../SpacerView';
-import tagPropTypes from '../tagPropTypes';
const propTypes = {
/** The report currently being looked at */
@@ -118,7 +118,7 @@ function MoneyRequestView({report, betas, parentReport, policyCategories, should
const policyTagsList = lodashGet(policyTag, 'tags', {});
// Flags for showing categories and tags
- const shouldShowCategory = isPolicyExpenseChat && Permissions.canUseCategories(betas) && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories)));
+ const shouldShowCategory = isPolicyExpenseChat && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories)));
const shouldShowTag = isPolicyExpenseChat && Permissions.canUseTags(betas) && (transactionTag || OptionsListUtils.hasEnabledOptions(lodashValues(policyTagsList)));
const shouldShowBillable = isPolicyExpenseChat && Permissions.canUseTags(betas) && (transactionBillable || !lodashGet(policy, 'disabledFields.defaultBillable', true));
diff --git a/src/components/ReportActionItem/RenameAction.js b/src/components/ReportActionItem/RenameAction.js
index 5e81abd0917b..e9158dcf1c37 100644
--- a/src/components/ReportActionItem/RenameAction.js
+++ b/src/components/ReportActionItem/RenameAction.js
@@ -1,12 +1,12 @@
-import React from 'react';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
-import Text from '../Text';
-import styles from '../../styles/styles';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import compose from '../../libs/compose';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails';
+import PropTypes from 'prop-types';
+import React from 'react';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import styles from '@styles/styles';
const propTypes = {
/** All the data of the action */
diff --git a/src/components/ReportActionItem/ReportActionItemImage.js b/src/components/ReportActionItem/ReportActionItemImage.js
index f17a1f1929fe..ff4b94443940 100644
--- a/src/components/ReportActionItem/ReportActionItemImage.js
+++ b/src/components/ReportActionItem/ReportActionItemImage.js
@@ -1,20 +1,20 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import Image from '../Image';
-import ThumbnailImage from '../ThumbnailImage';
-import tryResolveUrlFromApiRoot from '../../libs/tryResolveUrlFromApiRoot';
-import ROUTES from '../../ROUTES';
-import CONST from '../../CONST';
-import {ShowContextMenuContext} from '../ShowContextMenuContext';
-import Navigation from '../../libs/Navigation/Navigation';
-import PressableWithoutFocus from '../Pressable/PressableWithoutFocus';
-import useLocalize from '../../hooks/useLocalize';
-import EReceiptThumbnail from '../EReceiptThumbnail';
-import transactionPropTypes from '../transactionPropTypes';
-import * as TransactionUtils from '../../libs/TransactionUtils';
+import EReceiptThumbnail from '@components/EReceiptThumbnail';
+import Image from '@components/Image';
+import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
+import {ShowContextMenuContext} from '@components/ShowContextMenuContext';
+import ThumbnailImage from '@components/ThumbnailImage';
+import transactionPropTypes from '@components/transactionPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** thumbnail URI for the image */
diff --git a/src/components/ReportActionItem/ReportActionItemImages.js b/src/components/ReportActionItem/ReportActionItemImages.js
index bd1ee6d45a07..b41307864de6 100644
--- a/src/components/ReportActionItem/ReportActionItemImages.js
+++ b/src/components/ReportActionItem/ReportActionItemImages.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import Text from '../Text';
+import Text from '@components/Text';
+import transactionPropTypes from '@components/transactionPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
import ReportActionItemImage from './ReportActionItemImage';
-import * as StyleUtils from '../../styles/StyleUtils';
-import variables from '../../styles/variables';
-import transactionPropTypes from '../transactionPropTypes';
const propTypes = {
/** array of image and thumbnail URIs */
diff --git a/src/components/ReportActionItem/ReportPreview.js b/src/components/ReportActionItem/ReportPreview.js
index bdeec2640cdc..00a4526b382f 100644
--- a/src/components/ReportActionItem/ReportPreview.js
+++ b/src/components/ReportActionItem/ReportPreview.js
@@ -1,36 +1,36 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'underscore';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import Button from '../Button';
-import Icon from '../Icon';
-import Text from '../Text';
-import * as Expensicons from '../Icon/Expensicons';
-import styles from '../../styles/styles';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import compose from '../../libs/compose';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
-import ControlSelection from '../../libs/ControlSelection';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import {showContextMenuForReport} from '../ShowContextMenuContext';
-import * as CurrencyUtils from '../../libs/CurrencyUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import useLocalize from '../../hooks/useLocalize';
-import SettlementButton from '../SettlementButton';
-import * as IOU from '../../libs/actions/IOU';
-import refPropTypes from '../refPropTypes';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import themeColors from '../../styles/themes/default';
-import reportPropTypes from '../../pages/reportPropTypes';
-import * as ReceiptUtils from '../../libs/ReceiptUtils';
-import * as ReportActionUtils from '../../libs/ReportActionsUtils';
-import * as TransactionUtils from '../../libs/TransactionUtils';
+import _ from 'underscore';
+import Button from '@components/Button';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import refPropTypes from '@components/refPropTypes';
+import SettlementButton from '@components/SettlementButton';
+import {showContextMenuForReport} from '@components/ShowContextMenuContext';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import ControlSelection from '@libs/ControlSelection';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReceiptUtils from '@libs/ReceiptUtils';
+import * as ReportActionUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import ReportActionItemImages from './ReportActionItemImages';
const propTypes = {
diff --git a/src/components/ReportActionItem/TaskAction.js b/src/components/ReportActionItem/TaskAction.js
index 9d32fa7a1e77..db4239371e44 100644
--- a/src/components/ReportActionItem/TaskAction.js
+++ b/src/components/ReportActionItem/TaskAction.js
@@ -1,10 +1,10 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import Text from '../Text';
-import styles from '../../styles/styles';
-import * as Task from '../../libs/actions/Task';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
const propTypes = {
/** Name of the reportAction action */
diff --git a/src/components/ReportActionItem/TaskPreview.js b/src/components/ReportActionItem/TaskPreview.js
index 3499aee5f682..63ece9fcb3e1 100644
--- a/src/components/ReportActionItem/TaskPreview.js
+++ b/src/components/ReportActionItem/TaskPreview.js
@@ -1,30 +1,30 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import compose from '../../libs/compose';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../withCurrentUserPersonalDetails';
-import Icon from '../Icon';
-import CONST from '../../CONST';
-import * as Expensicons from '../Icon/Expensicons';
-import Checkbox from '../Checkbox';
-import * as StyleUtils from '../../styles/StyleUtils';
-import getButtonState from '../../libs/getButtonState';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import reportActionPropTypes from '../../pages/home/report/reportActionPropTypes';
-import * as Task from '../../libs/actions/Task';
-import * as ReportUtils from '../../libs/ReportUtils';
-import RenderHTML from '../RenderHTML';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import personalDetailsPropType from '../../pages/personalDetailsPropType';
-import * as Session from '../../libs/actions/Session';
-import * as LocalePhoneNumber from '../../libs/LocalePhoneNumber';
+import Checkbox from '@components/Checkbox';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import RenderHTML from '@components/RenderHTML';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import getButtonState from '@libs/getButtonState';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as Session from '@userActions/Session';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** All personal details asssociated with user */
diff --git a/src/components/ReportActionItem/TaskView.js b/src/components/ReportActionItem/TaskView.js
index 7cddc7a969dc..9aa85392dde7 100644
--- a/src/components/ReportActionItem/TaskView.js
+++ b/src/components/ReportActionItem/TaskView.js
@@ -1,33 +1,33 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useEffect} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import reportPropTypes from '../../pages/reportPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import withWindowDimensions from '../withWindowDimensions';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../withCurrentUserPersonalDetails';
-import compose from '../../libs/compose';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import MenuItemWithTopDescription from '../MenuItemWithTopDescription';
-import Hoverable from '../Hoverable';
-import MenuItem from '../MenuItem';
-import OfflineWithFeedback from '../OfflineWithFeedback';
-import styles from '../../styles/styles';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import * as StyleUtils from '../../styles/StyleUtils';
-import * as Task from '../../libs/actions/Task';
-import CONST from '../../CONST';
-import Checkbox from '../Checkbox';
-import convertToLTR from '../../libs/convertToLTR';
-import Text from '../Text';
-import Icon from '../Icon';
-import getButtonState from '../../libs/getButtonState';
-import PressableWithSecondaryInteraction from '../PressableWithSecondaryInteraction';
-import * as Session from '../../libs/actions/Session';
-import * as Expensicons from '../Icon/Expensicons';
-import SpacerView from '../SpacerView';
+import Checkbox from '@components/Checkbox';
+import Hoverable from '@components/Hoverable';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import SpacerView from '@components/SpacerView';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import convertToLTR from '@libs/convertToLTR';
+import getButtonState from '@libs/getButtonState';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as Session from '@userActions/Session';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** The report currently being looked at */
@@ -47,11 +47,13 @@ function TaskView(props) {
}, [props.report]);
const taskTitle = convertToLTR(props.report.reportName || '');
+ const assigneeTooltipDetails = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs([props.report.managerID], props.personalDetails), false);
const isCompleted = ReportUtils.isCompletedTaskReport(props.report);
const isOpen = ReportUtils.isOpenTaskReport(props.report);
const canModifyTask = Task.canModifyTask(props.report, props.currentUserPersonalDetails.accountID);
const disableState = !canModifyTask;
const isDisableInteractive = !canModifyTask || !isOpen;
+
return (
) : (
diff --git a/src/components/ReportActionsSkeletonView/SkeletonViewLines.js b/src/components/ReportActionsSkeletonView/SkeletonViewLines.js
index e4432ceb2309..1811c14e4695 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 React from 'react';
import SkeletonViewContentLoader from 'react-content-loader/native';
-import CONST from '../../CONST';
-import themeColors from '../../styles/themes/default';
-import styles from '../../styles/styles';
+import {Circle, Rect} from 'react-native-svg';
+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 */
diff --git a/src/components/ReportActionsSkeletonView/index.js b/src/components/ReportActionsSkeletonView/index.js
index 6bdc993c2055..6087510a53b0 100644
--- a/src/components/ReportActionsSkeletonView/index.js
+++ b/src/components/ReportActionsSkeletonView/index.js
@@ -1,29 +1,32 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import {View, Dimensions} from 'react-native';
+import React from 'react';
+import {Dimensions, View} from 'react-native';
+import CONST from '@src/CONST';
import SkeletonViewLines from './SkeletonViewLines';
-import CONST from '../../CONST';
const propTypes = {
/** Whether to animate the skeleton view */
shouldAnimate: PropTypes.bool,
+
+ /** Number of possible visible content items */
+ possibleVisibleContentItems: PropTypes.number,
};
const defaultProps = {
shouldAnimate: true,
+ possibleVisibleContentItems: 0,
};
-function ReportActionsSkeletonView(props) {
- // Determines the number of content items based on container height
- const possibleVisibleContentItems = Math.ceil(Dimensions.get('window').height / CONST.CHAT_SKELETON_VIEW.AVERAGE_ROW_HEIGHT);
+function ReportActionsSkeletonView({shouldAnimate, possibleVisibleContentItems}) {
+ const contentItems = possibleVisibleContentItems || Math.ceil(Dimensions.get('window').height / CONST.CHAT_SKELETON_VIEW.AVERAGE_ROW_HEIGHT);
const skeletonViewLines = [];
- for (let index = 0; index < possibleVisibleContentItems; index++) {
+ for (let index = 0; index < contentItems; index++) {
const iconIndex = (index + 1) % 4;
switch (iconIndex) {
case 2:
skeletonViewLines.push(
,
@@ -32,7 +35,7 @@ function ReportActionsSkeletonView(props) {
case 0:
skeletonViewLines.push(
,
@@ -41,7 +44,7 @@ function ReportActionsSkeletonView(props) {
default:
skeletonViewLines.push(
,
diff --git a/src/components/ReportHeaderSkeletonView.js b/src/components/ReportHeaderSkeletonView.js
index 5f2d5379419d..f2001094f60a 100644
--- a/src/components/ReportHeaderSkeletonView.js
+++ b/src/components/ReportHeaderSkeletonView.js
@@ -1,18 +1,18 @@
+import PropTypes from 'prop-types';
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 {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';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
-import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
-import variables from '../styles/variables';
-import themeColors from '../styles/themes/default';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
-import compose from '../libs/compose';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import CONST from '../CONST';
+import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
const propTypes = {
...windowDimensionsPropTypes,
diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js
index 23a27682a7d4..e1a6d4d4f6c1 100644
--- a/src/components/ReportWelcomeText.js
+++ b/src/components/ReportWelcomeText.js
@@ -1,22 +1,22 @@
-import React from 'react';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import UserDetailsTooltip from './UserDetailsTooltip';
-import styles from '../styles/styles';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import Text from './Text';
+import UserDetailsTooltip from './UserDetailsTooltip';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import compose from '../libs/compose';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import ONYXKEYS from '../ONYXKEYS';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
-import reportPropTypes from '../pages/reportPropTypes';
-import CONST from '../CONST';
const personalDetailsPropTypes = PropTypes.shape({
/** The login of the person (either email or phone number) */
diff --git a/src/components/RoomHeaderAvatars.js b/src/components/RoomHeaderAvatars.js
index 36af74bcdac9..6f191f82ba35 100644
--- a/src/components/RoomHeaderAvatars.js
+++ b/src/components/RoomHeaderAvatars.js
@@ -1,17 +1,17 @@
-import React, {memo} from 'react';
import PropTypes from 'prop-types';
+import React, {memo} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../styles/styles';
-import Text from './Text';
-import CONST from '../CONST';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import AttachmentModal from './AttachmentModal';
import Avatar from './Avatar';
-import themeColors from '../styles/themes/default';
-import * as StyleUtils from '../styles/StyleUtils';
import avatarPropTypes from './avatarPropTypes';
import PressableWithoutFocus from './Pressable/PressableWithoutFocus';
-import * as UserUtils from '../libs/UserUtils';
-import AttachmentModal from './AttachmentModal';
+import Text from './Text';
const propTypes = {
icons: PropTypes.arrayOf(avatarPropTypes),
diff --git a/src/components/RoomNameInput/index.js b/src/components/RoomNameInput/index.js
index 37d131108e9e..3f23a47d5f00 100644
--- a/src/components/RoomNameInput/index.js
+++ b/src/components/RoomNameInput/index.js
@@ -1,10 +1,10 @@
import React, {useState} from 'react';
import _ from 'underscore';
-import CONST from '../../CONST';
-import TextInput from '../TextInput';
-import useLocalize from '../../hooks/useLocalize';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import * as RoomNameInputUtils from '@libs/RoomNameInputUtils';
+import CONST from '@src/CONST';
import * as roomNameInputPropTypes from './roomNameInputPropTypes';
-import * as RoomNameInputUtils from '../../libs/RoomNameInputUtils';
function RoomNameInput({isFocused, autoFocus, disabled, errorText, forwardedRef, value, onBlur, onChangeText, onInputChange, shouldDelayFocus}) {
const {translate} = useLocalize();
@@ -71,10 +71,14 @@ RoomNameInput.propTypes = roomNameInputPropTypes.propTypes;
RoomNameInput.defaultProps = roomNameInputPropTypes.defaultProps;
RoomNameInput.displayName = 'RoomNameInput';
-export default React.forwardRef((props, ref) => (
+const RoomNameInputWithRef = React.forwardRef((props, ref) => (
));
+
+RoomNameInputWithRef.displayName = 'RoomNameInputWithRef';
+
+export default RoomNameInputWithRef;
diff --git a/src/components/RoomNameInput/index.native.js b/src/components/RoomNameInput/index.native.js
index 78500a8f0be2..d9b592b1537d 100644
--- a/src/components/RoomNameInput/index.native.js
+++ b/src/components/RoomNameInput/index.native.js
@@ -1,11 +1,11 @@
import React from 'react';
import _ from 'underscore';
-import CONST from '../../CONST';
-import useLocalize from '../../hooks/useLocalize';
-import TextInput from '../TextInput';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import getOperatingSystem from '@libs/getOperatingSystem';
+import * as RoomNameInputUtils from '@libs/RoomNameInputUtils';
+import CONST from '@src/CONST';
import * as roomNameInputPropTypes from './roomNameInputPropTypes';
-import * as RoomNameInputUtils from '../../libs/RoomNameInputUtils';
-import getOperatingSystem from '../../libs/getOperatingSystem';
function RoomNameInput({isFocused, autoFocus, disabled, errorText, forwardedRef, value, onBlur, onChangeText, onInputChange, shouldDelayFocus}) {
const {translate} = useLocalize();
@@ -53,10 +53,14 @@ RoomNameInput.propTypes = roomNameInputPropTypes.propTypes;
RoomNameInput.defaultProps = roomNameInputPropTypes.defaultProps;
RoomNameInput.displayName = 'RoomNameInput';
-export default React.forwardRef((props, ref) => (
+const RoomNameInputWithRef = React.forwardRef((props, ref) => (
));
+
+RoomNameInputWithRef.displayName = 'RoomNameInputWithRef';
+
+export default RoomNameInputWithRef;
diff --git a/src/components/SVGImage/index.js b/src/components/SVGImage/index.js
index 7374539509e2..de915007cc29 100644
--- a/src/components/SVGImage/index.js
+++ b/src/components/SVGImage/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import {Image} from 'react-native';
-import * as StyleUtils from '../../styles/StyleUtils';
+import * as StyleUtils from '@styles/StyleUtils';
import propTypes from './propTypes';
function SVGImage(props) {
diff --git a/src/components/SafeArea/index.ios.js b/src/components/SafeArea/index.ios.js
index ba9b1f01e298..2ef716d0e977 100644
--- a/src/components/SafeArea/index.ios.js
+++ b/src/components/SafeArea/index.ios.js
@@ -1,7 +1,7 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {SafeAreaView} from 'react-native-safe-area-context';
-import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
+import styles from '@styles/styles';
function SafeArea(props) {
return (
diff --git a/src/components/SafeAreaConsumer.js b/src/components/SafeAreaConsumer.js
index 78d7426ba380..25f22ed61ec4 100644
--- a/src/components/SafeAreaConsumer.js
+++ b/src/components/SafeAreaConsumer.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
-import * as StyleUtils from '../styles/StyleUtils';
+import * as StyleUtils from '@styles/StyleUtils';
const propTypes = {
/** Children to render. */
diff --git a/src/components/ScreenWrapper/index.js b/src/components/ScreenWrapper/index.js
index e2af40589a8a..0b6b742b1a67 100644
--- a/src/components/ScreenWrapper/index.js
+++ b/src/components/ScreenWrapper/index.js
@@ -1,24 +1,24 @@
-import {Keyboard, View, PanResponder} from 'react-native';
-import React, {useEffect, useRef, useState} from 'react';
-import _ from 'underscore';
+import {useNavigation} from '@react-navigation/native';
import lodashGet from 'lodash/get';
+import React, {useEffect, useRef, useState} from 'react';
+import {Keyboard, PanResponder, View} from 'react-native';
import {PickerAvoidingView} from 'react-native-picker-select';
-import {useNavigation} from '@react-navigation/native';
-import KeyboardAvoidingView from '../KeyboardAvoidingView';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import HeaderGap from '../HeaderGap';
-import OfflineIndicator from '../OfflineIndicator';
-import {propTypes, defaultProps} from './propTypes';
-import SafeAreaConsumer from '../SafeAreaConsumer';
-import TestToolsModal from '../TestToolsModal';
-import toggleTestToolsModal from '../../libs/actions/TestTool';
-import CustomDevMenu from '../CustomDevMenu';
-import * as Browser from '../../libs/Browser';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import useKeyboardState from '../../hooks/useKeyboardState';
-import useEnvironment from '../../hooks/useEnvironment';
-import useNetwork from '../../hooks/useNetwork';
+import _ from 'underscore';
+import CustomDevMenu from '@components/CustomDevMenu';
+import HeaderGap from '@components/HeaderGap';
+import KeyboardAvoidingView from '@components/KeyboardAvoidingView';
+import OfflineIndicator from '@components/OfflineIndicator';
+import SafeAreaConsumer from '@components/SafeAreaConsumer';
+import TestToolsModal from '@components/TestToolsModal';
+import useEnvironment from '@hooks/useEnvironment';
+import useKeyboardState from '@hooks/useKeyboardState';
+import useNetwork from '@hooks/useNetwork';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import styles from '@styles/styles';
+import toggleTestToolsModal from '@userActions/TestTool';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes} from './propTypes';
function ScreenWrapper({
shouldEnableMaxHeight,
diff --git a/src/components/ScreenWrapper/propTypes.js b/src/components/ScreenWrapper/propTypes.js
index 848aa28cde43..76c0f81975e4 100644
--- a/src/components/ScreenWrapper/propTypes.js
+++ b/src/components/ScreenWrapper/propTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import stylePropTypes from '../../styles/stylePropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
const propTypes = {
/** Array of additional styles to add */
diff --git a/src/components/ScrollViewWithContext.js b/src/components/ScrollViewWithContext.js
index 1d183e250767..0773f7496d12 100644
--- a/src/components/ScrollViewWithContext.js
+++ b/src/components/ScrollViewWithContext.js
@@ -1,4 +1,4 @@
-import React, {useState, useRef, useMemo} from 'react';
+import React, {useMemo, useRef, useState} from 'react';
import {ScrollView} from 'react-native';
const MIN_SMOOTH_SCROLL_EVENT_THROTTLE = 16;
@@ -51,11 +51,15 @@ function ScrollViewWithContext({onScroll, scrollEventThrottle, children, innerRe
ScrollViewWithContext.propTypes = propTypes;
ScrollViewWithContext.displayName = 'ScrollViewWithContext';
-export default React.forwardRef((props, ref) => (
+const ScrollViewWithContextWithRef = React.forwardRef((props, ref) => (
));
+
+ScrollViewWithContextWithRef.displayName = 'ScrollViewWithContextWithRef';
+
+export default ScrollViewWithContextWithRef;
export {ScrollContext};
diff --git a/src/components/Section.js b/src/components/Section.js
index c0b07d1c1453..d2e1069bec37 100644
--- a/src/components/Section.js
+++ b/src/components/Section.js
@@ -1,11 +1,11 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from './Text';
-import styles from '../styles/styles';
-import MenuItemList from './MenuItemList';
+import styles from '@styles/styles';
import Icon from './Icon';
+import MenuItemList from './MenuItemList';
import menuItemPropTypes from './menuItemPropTypes';
+import Text from './Text';
const propTypes = {
/** An array of props that are pass to individual MenuItem components */
diff --git a/src/components/SectionList/index.android.js b/src/components/SectionList/index.android.js
index 7fc74277a281..d214e1748bf4 100644
--- a/src/components/SectionList/index.android.js
+++ b/src/components/SectionList/index.android.js
@@ -1,7 +1,7 @@
import React, {forwardRef} from 'react';
import {SectionList} from 'react-native';
-export default forwardRef((props, ref) => (
+const SectionListWithRef = forwardRef((props, ref) => (
(
removeClippedSubviews
/>
));
+
+SectionListWithRef.displayName = 'SectionListWithRef';
+
+export default SectionListWithRef;
diff --git a/src/components/SelectCircle.js b/src/components/SelectCircle.js
index 55e410f8baa1..ce451e148030 100644
--- a/src/components/SelectCircle.js
+++ b/src/components/SelectCircle.js
@@ -1,10 +1,10 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
import Icon from './Icon';
import * as Expensicons from './Icon/Expensicons';
-import themeColors from '../styles/themes/default';
const propTypes = {
/** Should we show the checkmark inside the circle */
diff --git a/src/components/SelectionList/BaseListItem.js b/src/components/SelectionList/BaseListItem.js
index 171a58ee9fa9..3dd4417367b2 100644
--- a/src/components/SelectionList/BaseListItem.js
+++ b/src/components/SelectionList/BaseListItem.js
@@ -1,17 +1,19 @@
+import lodashGet from 'lodash/get';
import React from 'react';
import {View} from 'react-native';
-import lodashGet from 'lodash/get';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import themeColors from '../../styles/themes/default';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import RadioListItem from './RadioListItem';
import {baseListItemPropTypes} from './selectionListPropTypes';
-import * as StyleUtils from '../../styles/StyleUtils';
import UserListItem from './UserListItem';
-import RadioListItem from './RadioListItem';
-import OfflineWithFeedback from '../OfflineWithFeedback';
-import CONST from '../../CONST';
function BaseListItem({
item,
@@ -23,6 +25,7 @@ function BaseListItem({
onSelectRow,
onDismissError = () => {},
}) {
+ const {translate} = useLocalize();
const isUserItem = lodashGet(item, 'icons.length', 0) > 0;
const ListItem = isUserItem ? UserListItem : RadioListItem;
@@ -76,7 +79,6 @@ function BaseListItem({
)}
-
-
{!canSelectMultiple && item.isSelected && (
)}
+ {Boolean(item.invitedSecondaryLogin) && (
+
+ {translate('workspace.people.invitedBySecondaryLogin', {secondaryLogin: item.invitedSecondaryLogin})}
+
+ )}
);
diff --git a/src/components/SelectionList/BaseSelectionList.js b/src/components/SelectionList/BaseSelectionList.js
index fdb1f92ca73b..65f98828dca7 100644
--- a/src/components/SelectionList/BaseSelectionList.js
+++ b/src/components/SelectionList/BaseSelectionList.js
@@ -1,29 +1,29 @@
+import {useFocusEffect, useIsFocused} from '@react-navigation/native';
+import lodashGet from 'lodash/get';
import React, {useCallback, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import {useFocusEffect, useIsFocused} from '@react-navigation/native';
-import SectionList from '../SectionList';
-import Text from '../Text';
-import styles from '../../styles/styles';
-import TextInput from '../TextInput';
-import CONST from '../../CONST';
-import variables from '../../styles/variables';
-import {propTypes as selectionListPropTypes} from './selectionListPropTypes';
-import useKeyboardShortcut from '../../hooks/useKeyboardShortcut';
-import SafeAreaConsumer from '../SafeAreaConsumer';
-import withKeyboardState, {keyboardStatePropTypes} from '../withKeyboardState';
-import Checkbox from '../Checkbox';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
-import FixedFooter from '../FixedFooter';
-import Button from '../Button';
-import useLocalize from '../../hooks/useLocalize';
-import Log from '../../libs/Log';
-import OptionsListSkeletonView from '../OptionsListSkeletonView';
-import useActiveElement from '../../hooks/useActiveElement';
+import ArrowKeyFocusManager from '@components/ArrowKeyFocusManager';
+import Button from '@components/Button';
+import Checkbox from '@components/Checkbox';
+import FixedFooter from '@components/FixedFooter';
+import OptionsListSkeletonView from '@components/OptionsListSkeletonView';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import SafeAreaConsumer from '@components/SafeAreaConsumer';
+import SectionList from '@components/SectionList';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withKeyboardState, {keyboardStatePropTypes} from '@components/withKeyboardState';
+import useActiveElement from '@hooks/useActiveElement';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
+import useLocalize from '@hooks/useLocalize';
+import Log from '@libs/Log';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import BaseListItem from './BaseListItem';
-import ArrowKeyFocusManager from '../ArrowKeyFocusManager';
-import themeColors from '../../styles/themes/default';
+import {propTypes as selectionListPropTypes} from './selectionListPropTypes';
const propTypes = {
...keyboardStatePropTypes,
@@ -48,6 +48,7 @@ function BaseSelectionList({
headerMessage = '',
confirmButtonText = '',
onConfirm,
+ headerContent,
footerContent,
showScrollIndicator = false,
showLoadingPlaceholder = false,
@@ -152,31 +153,33 @@ function BaseSelectionList({
* @param {Number} index - the index of the item to scroll to
* @param {Boolean} animated - whether to animate the scroll
*/
- const scrollToIndex = useCallback((index, animated = true) => {
- const item = flattenedSections.allOptions[index];
+ const scrollToIndex = useCallback(
+ (index, animated = true) => {
+ const item = flattenedSections.allOptions[index];
- if (!listRef.current || !item) {
- return;
- }
+ if (!listRef.current || !item) {
+ return;
+ }
- const itemIndex = item.index;
- const sectionIndex = item.sectionIndex;
+ const itemIndex = item.index;
+ const sectionIndex = item.sectionIndex;
- // Note: react-native's SectionList automatically strips out any empty sections.
- // So we need to reduce the sectionIndex to remove any empty sections in front of the one we're trying to scroll to.
- // Otherwise, it will cause an index-out-of-bounds error and crash the app.
- let adjustedSectionIndex = sectionIndex;
- for (let i = 0; i < sectionIndex; i++) {
- if (_.isEmpty(lodashGet(sections, `[${i}].data`))) {
- adjustedSectionIndex--;
+ // Note: react-native's SectionList automatically strips out any empty sections.
+ // So we need to reduce the sectionIndex to remove any empty sections in front of the one we're trying to scroll to.
+ // Otherwise, it will cause an index-out-of-bounds error and crash the app.
+ let adjustedSectionIndex = sectionIndex;
+ for (let i = 0; i < sectionIndex; i++) {
+ if (_.isEmpty(lodashGet(sections, `[${i}].data`))) {
+ adjustedSectionIndex--;
+ }
}
- }
- listRef.current.scrollToLocation({sectionIndex: adjustedSectionIndex, itemIndex, animated, viewOffset: variables.contentHeaderHeight});
+ listRef.current.scrollToLocation({sectionIndex: adjustedSectionIndex, itemIndex, animated, viewOffset: variables.contentHeaderHeight});
+ },
- // If we don't disable dependencies here, we would need to make sure that the `sections` prop is stable in every usage of this component.
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ [flattenedSections.allOptions],
+ );
/**
* Logic to run when a row is selected, either with click/press or keyboard hotkeys.
@@ -389,6 +392,7 @@ function BaseSelectionList({
{headerMessage}
)}
+ {Boolean(headerContent) && headerContent}
{flattenedSections.allOptions.length === 0 && showLoadingPlaceholder ? (
) : (
diff --git a/src/components/SelectionList/RadioListItem.js b/src/components/SelectionList/RadioListItem.js
index 83d0fc922f08..0af064e20f8c 100644
--- a/src/components/SelectionList/RadioListItem.js
+++ b/src/components/SelectionList/RadioListItem.js
@@ -1,7 +1,7 @@
import React from 'react';
import {View} from 'react-native';
-import styles from '../../styles/styles';
-import Text from '../Text';
+import Text from '@components/Text';
+import styles from '@styles/styles';
import {radioListItemPropTypes} from './selectionListPropTypes';
function RadioListItem({item, isFocused = false}) {
diff --git a/src/components/SelectionList/UserListItem.js b/src/components/SelectionList/UserListItem.js
index 436ae8cb056b..6e4bd82357eb 100644
--- a/src/components/SelectionList/UserListItem.js
+++ b/src/components/SelectionList/UserListItem.js
@@ -1,11 +1,11 @@
+import lodashGet from 'lodash/get';
import React from 'react';
import {View} from 'react-native';
-import lodashGet from 'lodash/get';
-import styles from '../../styles/styles';
-import Text from '../Text';
+import SubscriptAvatar from '@components/SubscriptAvatar';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import styles from '@styles/styles';
import {userListItemPropTypes} from './selectionListPropTypes';
-import Tooltip from '../Tooltip';
-import SubscriptAvatar from '../SubscriptAvatar';
function UserListItem({item, isFocused = false, showTooltip}) {
return (
diff --git a/src/components/SelectionList/index.js b/src/components/SelectionList/index.js
index d2ad9ab3cf13..24ea60d29be5 100644
--- a/src/components/SelectionList/index.js
+++ b/src/components/SelectionList/index.js
@@ -1,7 +1,7 @@
import React, {forwardRef, useEffect, useState} from 'react';
import {Keyboard} from 'react-native';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import BaseSelectionList from './BaseSelectionList';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
const SelectionList = forwardRef((props, ref) => {
const [isScreenTouched, setIsScreenTouched] = useState(false);
diff --git a/src/components/SelectionList/selectionListPropTypes.js b/src/components/SelectionList/selectionListPropTypes.js
index e75335e39b23..2b53f555134e 100644
--- a/src/components/SelectionList/selectionListPropTypes.js
+++ b/src/components/SelectionList/selectionListPropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import _ from 'underscore';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
const commonListItemPropTypes = {
/** Whether this item is focused (for arrow key controls) */
@@ -174,6 +174,9 @@ const propTypes = {
/** A ref to forward to the TextInput */
inputRef: PropTypes.oneOfType([PropTypes.object]),
+ /** Custom content to display in the header */
+ headerContent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
+
/** Custom content to display in the footer */
footerContent: PropTypes.oneOfType([PropTypes.func, PropTypes.node]),
};
diff --git a/src/components/SettlementButton.js b/src/components/SettlementButton.js
index 2989fd103850..d2030eac8d7d 100644
--- a/src/components/SettlementButton.js
+++ b/src/components/SettlementButton.js
@@ -1,22 +1,22 @@
-import React, {useEffect, useMemo} from 'react';
-import _ from 'underscore';
import PropTypes from 'prop-types';
+import React, {useEffect, useMemo} from 'react';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import compose from '../libs/compose';
-import Permissions from '../libs/Permissions';
-import useNetwork from '../hooks/useNetwork';
-import useLocalize from '../hooks/useLocalize';
-import * as ReportUtils from '../libs/ReportUtils';
-import iouReportPropTypes from '../pages/iouReportPropTypes';
-import * as PaymentMethods from '../libs/actions/PaymentMethods';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import compose from '@libs/compose';
+import Permissions from '@libs/Permissions';
+import * as ReportUtils from '@libs/ReportUtils';
+import iouReportPropTypes from '@pages/iouReportPropTypes';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import ButtonWithDropdownMenu from './ButtonWithDropdownMenu';
+import * as Expensicons from './Icon/Expensicons';
import KYCWall from './KYCWall';
import withNavigation from './withNavigation';
-import * as Expensicons from './Icon/Expensicons';
-import ButtonWithDropdownMenu from './ButtonWithDropdownMenu';
-import * as BankAccounts from '../libs/actions/BankAccounts';
-import ROUTES from '../ROUTES';
const propTypes = {
/** Callback to execute when this button is pressed. Receives a single payment type argument. */
diff --git a/src/components/ShowContextMenuContext.js b/src/components/ShowContextMenuContext.js
index fff233162d74..6248478e5fea 100644
--- a/src/components/ShowContextMenuContext.js
+++ b/src/components/ShowContextMenuContext.js
@@ -1,8 +1,8 @@
import React from 'react';
-import * as ReportActionContextMenu from '../pages/home/report/ContextMenu/ReportActionContextMenu';
-import * as ContextMenuActions from '../pages/home/report/ContextMenu/ContextMenuActions';
-import * as DeviceCapabilities from '../libs/DeviceCapabilities';
-import * as ReportUtils from '../libs/ReportUtils';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as ContextMenuActions from '@pages/home/report/ContextMenu/ContextMenuActions';
+import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
const ShowContextMenuContext = React.createContext({
anchor: null,
diff --git a/src/components/SignInButtons/AppleAuthWrapper/index.ios.js b/src/components/SignInButtons/AppleAuthWrapper/index.ios.js
index 9f97182b2e7b..69882d89b1fe 100644
--- a/src/components/SignInButtons/AppleAuthWrapper/index.ios.js
+++ b/src/components/SignInButtons/AppleAuthWrapper/index.ios.js
@@ -1,6 +1,6 @@
-import {useEffect} from 'react';
import appleAuth from '@invertase/react-native-apple-authentication';
-import * as Session from '../../../libs/actions/Session';
+import {useEffect} from 'react';
+import * as Session from '@userActions/Session';
/**
* Apple Sign In wrapper for iOS
diff --git a/src/components/SignInButtons/AppleSignIn/index.android.js b/src/components/SignInButtons/AppleSignIn/index.android.js
index 48d2bf3cc861..9dc736789c61 100644
--- a/src/components/SignInButtons/AppleSignIn/index.android.js
+++ b/src/components/SignInButtons/AppleSignIn/index.android.js
@@ -1,10 +1,10 @@
-import React from 'react';
import {appleAuthAndroid} from '@invertase/react-native-apple-authentication';
-import Log from '../../../libs/Log';
-import IconButton from '../IconButton';
-import * as Session from '../../../libs/actions/Session';
-import CONFIG from '../../../CONFIG';
-import CONST from '../../../CONST';
+import React from 'react';
+import IconButton from '@components/SignInButtons/IconButton';
+import Log from '@libs/Log';
+import * as Session from '@userActions/Session';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
/**
* Apple Sign In Configuration for Android.
diff --git a/src/components/SignInButtons/AppleSignIn/index.desktop.js b/src/components/SignInButtons/AppleSignIn/index.desktop.js
index 52ff3ef710b0..cad37d585de4 100644
--- a/src/components/SignInButtons/AppleSignIn/index.desktop.js
+++ b/src/components/SignInButtons/AppleSignIn/index.desktop.js
@@ -1,10 +1,10 @@
import React from 'react';
import {View} from 'react-native';
-import IconButton from '../IconButton';
-import CONFIG from '../../../CONFIG';
-import ROUTES from '../../../ROUTES';
-import styles from '../../../styles/styles';
-import CONST from '../../../CONST';
+import IconButton from '@components/SignInButtons/IconButton';
+import styles from '@styles/styles';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const appleSignInWebRouteForDesktopFlow = `${CONFIG.EXPENSIFY.NEW_EXPENSIFY_URL}${ROUTES.APPLE_SIGN_IN}`;
diff --git a/src/components/SignInButtons/AppleSignIn/index.ios.js b/src/components/SignInButtons/AppleSignIn/index.ios.js
index 0c9a8c9e8211..f5c6333dcf7b 100644
--- a/src/components/SignInButtons/AppleSignIn/index.ios.js
+++ b/src/components/SignInButtons/AppleSignIn/index.ios.js
@@ -1,9 +1,9 @@
-import React from 'react';
import appleAuth from '@invertase/react-native-apple-authentication';
-import Log from '../../../libs/Log';
-import IconButton from '../IconButton';
-import * as Session from '../../../libs/actions/Session';
-import CONST from '../../../CONST';
+import React from 'react';
+import IconButton from '@components/SignInButtons/IconButton';
+import Log from '@libs/Log';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
/**
* Apple Sign In method for iOS that returns identityToken.
diff --git a/src/components/SignInButtons/AppleSignIn/index.website.js b/src/components/SignInButtons/AppleSignIn/index.website.js
index 7046de5068b1..adae0a691e13 100644
--- a/src/components/SignInButtons/AppleSignIn/index.website.js
+++ b/src/components/SignInButtons/AppleSignIn/index.website.js
@@ -1,13 +1,13 @@
-import React, {useEffect, useState} from 'react';
+import get from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useEffect, useState} from 'react';
import Config from 'react-native-config';
-import get from 'lodash/get';
-import getUserLanguage from '../GetUserLanguage';
-import * as Session from '../../../libs/actions/Session';
-import Log from '../../../libs/Log';
-import CONFIG from '../../../CONFIG';
-import CONST from '../../../CONST';
-import withNavigationFocus from '../../withNavigationFocus';
+import getUserLanguage from '@components/SignInButtons/GetUserLanguage';
+import withNavigationFocus from '@components/withNavigationFocus';
+import Log from '@libs/Log';
+import * as Session from '@userActions/Session';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
// react-native-config doesn't trim whitespace on iOS for some reason so we
// add a trim() call to lodashGet here to prevent headaches.
diff --git a/src/components/SignInButtons/GoogleSignIn/index.desktop.js b/src/components/SignInButtons/GoogleSignIn/index.desktop.js
index 95a78f34614b..e69905dcad05 100644
--- a/src/components/SignInButtons/GoogleSignIn/index.desktop.js
+++ b/src/components/SignInButtons/GoogleSignIn/index.desktop.js
@@ -1,11 +1,11 @@
import React from 'react';
import {View} from 'react-native';
-import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
-import IconButton from '../IconButton';
-import CONFIG from '../../../CONFIG';
-import ROUTES from '../../../ROUTES';
-import styles from '../../../styles/styles';
-import CONST from '../../../CONST';
+import IconButton from '@components/SignInButtons/IconButton';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {...withLocalizePropTypes};
diff --git a/src/components/SignInButtons/GoogleSignIn/index.native.js b/src/components/SignInButtons/GoogleSignIn/index.native.js
index 099fbfde22fd..c7ac763cfb73 100644
--- a/src/components/SignInButtons/GoogleSignIn/index.native.js
+++ b/src/components/SignInButtons/GoogleSignIn/index.native.js
@@ -1,10 +1,10 @@
-import React from 'react';
import {GoogleSignin, statusCodes} from '@react-native-google-signin/google-signin';
-import Log from '../../../libs/Log';
-import IconButton from '../IconButton';
-import * as Session from '../../../libs/actions/Session';
-import CONST from '../../../CONST';
-import CONFIG from '../../../CONFIG';
+import React from 'react';
+import IconButton from '@components/SignInButtons/IconButton';
+import Log from '@libs/Log';
+import * as Session from '@userActions/Session';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
/**
* Google Sign In method for iOS and android that returns identityToken.
diff --git a/src/components/SignInButtons/GoogleSignIn/index.website.js b/src/components/SignInButtons/GoogleSignIn/index.website.js
index 5362433142af..7f3a3019c318 100644
--- a/src/components/SignInButtons/GoogleSignIn/index.website.js
+++ b/src/components/SignInButtons/GoogleSignIn/index.website.js
@@ -1,10 +1,10 @@
+import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../withLocalize';
-import * as Session from '../../../libs/actions/Session';
-import CONFIG from '../../../CONFIG';
-import styles from '../../../styles/styles';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
+import CONFIG from '@src/CONFIG';
const propTypes = {
/** Whether we're rendering in the Desktop Flow, if so show a different button. */
diff --git a/src/components/SignInButtons/IconButton.js b/src/components/SignInButtons/IconButton.js
index 4f1692ddb677..0d18779ea9ba 100644
--- a/src/components/SignInButtons/IconButton.js
+++ b/src/components/SignInButtons/IconButton.js
@@ -1,11 +1,11 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import CONST from '../../CONST';
-import * as Expensicons from '../Icon/Expensicons';
-import Icon from '../Icon';
+import React from 'react';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** The on press method */
diff --git a/src/components/SignInPageForm/index.native.js b/src/components/SignInPageForm/index.native.js
deleted file mode 100644
index acd1dfe0d197..000000000000
--- a/src/components/SignInPageForm/index.native.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import React from 'react';
-import FormElement from '../FormElement';
-
-function Form(props) {
- // eslint-disable-next-line react/jsx-props-no-spreading
- return ;
-}
-
-Form.displayName = 'Form';
-export default Form;
diff --git a/src/components/SignInPageForm/index.native.tsx b/src/components/SignInPageForm/index.native.tsx
new file mode 100644
index 000000000000..b39e4d681bbe
--- /dev/null
+++ b/src/components/SignInPageForm/index.native.tsx
@@ -0,0 +1,12 @@
+import React from 'react';
+import FormElement from '@components/FormElement';
+import SignInPageFormProps from './types';
+
+function SignInPageForm(props: SignInPageFormProps) {
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ return ;
+}
+
+SignInPageForm.displayName = 'SignInPageForm';
+
+export default SignInPageForm;
diff --git a/src/components/SignInPageForm/index.js b/src/components/SignInPageForm/index.tsx
similarity index 77%
rename from src/components/SignInPageForm/index.js
rename to src/components/SignInPageForm/index.tsx
index 5a1e5a62ff23..1cdc31b33fd9 100644
--- a/src/components/SignInPageForm/index.js
+++ b/src/components/SignInPageForm/index.tsx
@@ -1,14 +1,15 @@
import React, {useEffect, useRef} from 'react';
-import FormElement from '../FormElement';
+import FormElement from '@components/FormElement';
+import SignInPageFormProps from './types';
-const preventFormDefault = (event) => {
+const preventFormDefault = (event: SubmitEvent) => {
// When enter is pressed form is submitted to action url (POST /).
// As we are using controlled component, we need to disable it here.
event.preventDefault();
};
-function Form(props) {
- const form = useRef(null);
+function SignInPageForm(props: SignInPageFormProps) {
+ const form = useRef(null);
useEffect(() => {
const formCurrent = form.current;
@@ -42,6 +43,6 @@ function Form(props) {
);
}
-Form.displayName = 'Form';
+SignInPageForm.displayName = 'SignInPageForm';
-export default Form;
+export default SignInPageForm;
diff --git a/src/components/SignInPageForm/types.ts b/src/components/SignInPageForm/types.ts
new file mode 100644
index 000000000000..02d948f917b9
--- /dev/null
+++ b/src/components/SignInPageForm/types.ts
@@ -0,0 +1,5 @@
+import {ViewProps} from 'react-native';
+
+type SignInPageFormProps = ViewProps;
+
+export default SignInPageFormProps;
diff --git a/src/components/SingleOptionSelector.js b/src/components/SingleOptionSelector.js
index 889b6a7d1f96..ef212937920e 100644
--- a/src/components/SingleOptionSelector.js
+++ b/src/components/SingleOptionSelector.js
@@ -1,12 +1,12 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React from 'react';
import {View} from 'react-native';
+import _ from 'underscore';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import SelectCircle from './SelectCircle';
-import styles from '../styles/styles';
-import CONST from '../CONST';
import Text from './Text';
-import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
diff --git a/src/components/SpacerView.js b/src/components/SpacerView.js
index 3b81bbfa0dc5..60ff7fd85e55 100644
--- a/src/components/SpacerView.js
+++ b/src/components/SpacerView.js
@@ -1,9 +1,9 @@
+import PropTypes from 'prop-types';
import React from 'react';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
-import PropTypes from 'prop-types';
-import * as StyleUtils from '../styles/StyleUtils';
-import stylePropTypes from '../styles/stylePropTypes';
-import CONST from '../CONST';
+import stylePropTypes from '@styles/stylePropTypes';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
const propTypes = {
/**
diff --git a/src/components/SplashScreenHider/index.js b/src/components/SplashScreenHider/index.js
index a3f3647ede81..9bbddd2a0891 100644
--- a/src/components/SplashScreenHider/index.js
+++ b/src/components/SplashScreenHider/index.js
@@ -1,6 +1,6 @@
-import {useEffect} from 'react';
import PropTypes from 'prop-types';
-import BootSplash from '../../libs/BootSplash';
+import {useEffect} from 'react';
+import BootSplash from '@libs/BootSplash';
const propTypes = {
/** Splash screen has been hidden */
diff --git a/src/components/SplashScreenHider/index.native.js b/src/components/SplashScreenHider/index.native.js
index dbfac3331484..711ce9f6fb80 100644
--- a/src/components/SplashScreenHider/index.native.js
+++ b/src/components/SplashScreenHider/index.native.js
@@ -1,10 +1,10 @@
-import {useCallback, useRef} from 'react';
import PropTypes from 'prop-types';
+import {useCallback, useRef} from 'react';
import {StyleSheet} from 'react-native';
-import Reanimated, {useSharedValue, withTiming, Easing, useAnimatedStyle, runOnJS} from 'react-native-reanimated';
-import BootSplash from '../../libs/BootSplash';
-import Logo from '../../../assets/images/new-expensify-dark.svg';
-import styles from '../../styles/styles';
+import Reanimated, {Easing, runOnJS, useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
+import Logo from '@assets/images/new-expensify-dark.svg';
+import BootSplash from '@libs/BootSplash';
+import styles from '@styles/styles';
const propTypes = {
/** Splash screen has been hidden */
diff --git a/src/components/StatePicker/StateSelectorModal.js b/src/components/StatePicker/StateSelectorModal.js
index 378dcc4ebc8b..8bda9d5303c8 100644
--- a/src/components/StatePicker/StateSelectorModal.js
+++ b/src/components/StatePicker/StateSelectorModal.js
@@ -1,16 +1,16 @@
-import _ from 'underscore';
-import React, {useMemo, useEffect} from 'react';
-import PropTypes from 'prop-types';
import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST';
-import CONST from '../../CONST';
-import Modal from '../Modal';
-import HeaderWithBackButton from '../HeaderWithBackButton';
-import SelectionList from '../SelectionList';
-import useLocalize from '../../hooks/useLocalize';
-import ScreenWrapper from '../ScreenWrapper';
-import styles from '../../styles/styles';
-import searchCountryOptions from '../../libs/searchCountryOptions';
-import StringUtils from '../../libs/StringUtils';
+import PropTypes from 'prop-types';
+import React, {useEffect, useMemo} from 'react';
+import _ from 'underscore';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Modal from '@components/Modal';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import useLocalize from '@hooks/useLocalize';
+import searchCountryOptions from '@libs/searchCountryOptions';
+import StringUtils from '@libs/StringUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether the modal is visible */
diff --git a/src/components/StatePicker/index.js b/src/components/StatePicker/index.js
index f7f894af2a07..c36c7e6b97a0 100644
--- a/src/components/StatePicker/index.js
+++ b/src/components/StatePicker/index.js
@@ -1,14 +1,14 @@
+import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST';
+import PropTypes from 'prop-types';
import React, {useState} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST';
-import styles from '../../styles/styles';
-import MenuItemWithTopDescription from '../MenuItemWithTopDescription';
-import useLocalize from '../../hooks/useLocalize';
-import FormHelpMessage from '../FormHelpMessage';
+import FormHelpMessage from '@components/FormHelpMessage';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import refPropTypes from '@components/refPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
import StateSelectorModal from './StateSelectorModal';
-import refPropTypes from '../refPropTypes';
const propTypes = {
/** Error text to display */
@@ -88,10 +88,14 @@ StatePicker.propTypes = propTypes;
StatePicker.defaultProps = defaultProps;
StatePicker.displayName = 'StatePicker';
-export default React.forwardRef((props, ref) => (
+const StatePickerWithRef = React.forwardRef((props, ref) => (
));
+
+StatePickerWithRef.displayName = 'StatePickerWithRef';
+
+export default StatePickerWithRef;
diff --git a/src/components/SubscriptAvatar.js b/src/components/SubscriptAvatar.js
index 66d9812d994e..4a232419aff7 100644
--- a/src/components/SubscriptAvatar.js
+++ b/src/components/SubscriptAvatar.js
@@ -1,13 +1,13 @@
-import React, {memo} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {memo} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import Avatar from './Avatar';
-import CONST from '../CONST';
-import * as StyleUtils from '../styles/StyleUtils';
import avatarPropTypes from './avatarPropTypes';
import UserDetailsTooltip from './UserDetailsTooltip';
diff --git a/src/components/SwipeableView/index.native.tsx b/src/components/SwipeableView/index.native.tsx
index ac500f025016..91d851101d4e 100644
--- a/src/components/SwipeableView/index.native.tsx
+++ b/src/components/SwipeableView/index.native.tsx
@@ -1,6 +1,6 @@
import React, {useRef} from 'react';
import {PanResponder, View} from 'react-native';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import SwipeableViewProps from './types';
function SwipeableView({children, onSwipeDown}: SwipeableViewProps) {
diff --git a/src/components/Switch.js b/src/components/Switch.js
index 5c8a0da925f3..755cd60f2597 100644
--- a/src/components/Switch.js
+++ b/src/components/Switch.js
@@ -1,10 +1,10 @@
import PropTypes from 'prop-types';
import React, {useEffect, useRef} from 'react';
import {Animated} from 'react-native';
-import CONST from '../CONST';
-import styles from '../styles/styles';
+import useNativeDriver from '@libs/useNativeDriver';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import PressableWithFeedback from './Pressable/PressableWithFeedback';
-import useNativeDriver from '../libs/useNativeDriver';
const propTypes = {
/** Whether the switch is toggled to the on position */
diff --git a/src/components/TabSelector/TabIcon.js b/src/components/TabSelector/TabIcon.js
index 85f1cd912ff6..d9d802d2076a 100644
--- a/src/components/TabSelector/TabIcon.js
+++ b/src/components/TabSelector/TabIcon.js
@@ -1,8 +1,8 @@
-import {StyleSheet, View, Animated} from 'react-native';
-import React from 'react';
import PropTypes from 'prop-types';
-import Icon from '../Icon';
-import themeColors from '../../styles/themes/default';
+import React from 'react';
+import {Animated, StyleSheet, View} from 'react-native';
+import Icon from '@components/Icon';
+import themeColors from '@styles/themes/default';
const propTypes = {
/** Icon to display on tab */
diff --git a/src/components/TabSelector/TabLabel.js b/src/components/TabSelector/TabLabel.js
index 32c8a384d814..9993e2fe4ed6 100644
--- a/src/components/TabSelector/TabLabel.js
+++ b/src/components/TabSelector/TabLabel.js
@@ -1,7 +1,7 @@
-import {StyleSheet, View, Text, Animated} from 'react-native';
-import React from 'react';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
+import React from 'react';
+import {Animated, StyleSheet, Text, View} from 'react-native';
+import styles from '@styles/styles';
const propTypes = {
/** Title of the tab */
diff --git a/src/components/TabSelector/TabSelector.js b/src/components/TabSelector/TabSelector.js
index 3483ec10f804..b6ee359dc4ca 100644
--- a/src/components/TabSelector/TabSelector.js
+++ b/src/components/TabSelector/TabSelector.js
@@ -1,13 +1,13 @@
-import {View} from 'react-native';
-import React, {useMemo, useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useMemo, useState} from 'react';
+import {View} from 'react-native';
import _ from 'underscore';
-import * as Expensicons from '../Icon/Expensicons';
+import * as Expensicons from '@components/Icon/Expensicons';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import TabSelectorItem from './TabSelectorItem';
-import CONST from '../../CONST';
-import useLocalize from '../../hooks/useLocalize';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
const propTypes = {
/* Navigation state provided by React Navigation */
diff --git a/src/components/TabSelector/TabSelectorItem.js b/src/components/TabSelector/TabSelectorItem.js
index 04a576f9dbf0..94861d0ccbba 100644
--- a/src/components/TabSelector/TabSelectorItem.js
+++ b/src/components/TabSelector/TabSelectorItem.js
@@ -1,8 +1,8 @@
-import {Animated, StyleSheet} from 'react-native';
-import React from 'react';
import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import PressableWithFeedback from '../Pressable/PressableWithFeedback';
+import React from 'react';
+import {Animated, StyleSheet} from 'react-native';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import styles from '@styles/styles';
import TabIcon from './TabIcon';
import TabLabel from './TabLabel';
diff --git a/src/components/TagPicker/index.js b/src/components/TagPicker/index.js
index 05eca664bd0f..d680cea15c8f 100644
--- a/src/components/TagPicker/index.js
+++ b/src/components/TagPicker/index.js
@@ -1,15 +1,15 @@
-import React, {useMemo, useState} from 'react';
-import _ from 'underscore';
import lodashGet from 'lodash/get';
+import React, {useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
-import styles from '../../styles/styles';
-import useLocalize from '../../hooks/useLocalize';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import OptionsSelector from '../OptionsSelector';
-import {propTypes, defaultProps} from './tagPickerPropTypes';
+import _ from 'underscore';
+import OptionsSelector from '@components/OptionsSelector';
+import useLocalize from '@hooks/useLocalize';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps, propTypes} from './tagPickerPropTypes';
function TagPicker({selectedTag, tag, policyTags, policyRecentlyUsedTags, onSubmit}) {
const {translate} = useLocalize();
diff --git a/src/components/TagPicker/tagPickerPropTypes.js b/src/components/TagPicker/tagPickerPropTypes.js
index 011885fe0f81..3010ab24a9c1 100644
--- a/src/components/TagPicker/tagPickerPropTypes.js
+++ b/src/components/TagPicker/tagPickerPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import tagPropTypes from '../tagPropTypes';
+import tagPropTypes from '@components/tagPropTypes';
const propTypes = {
/** The policyID we are getting tags for */
diff --git a/src/components/TaskHeaderActionButton.js b/src/components/TaskHeaderActionButton.js
index a16f415f0fd7..b5dbe49fdd8d 100644
--- a/src/components/TaskHeaderActionButton.js
+++ b/src/components/TaskHeaderActionButton.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import reportPropTypes from '../pages/reportPropTypes';
-import withLocalize, {withLocalizePropTypes} from './withLocalize';
-import styles from '../styles/styles';
+import compose from '@libs/compose';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import ONYXKEYS from '@src/ONYXKEYS';
import Button from './Button';
-import * as Task from '../libs/actions/Task';
-import * as ReportUtils from '../libs/ReportUtils';
-import compose from '../libs/compose';
-import ONYXKEYS from '../ONYXKEYS';
+import withLocalize, {withLocalizePropTypes} from './withLocalize';
const propTypes = {
/** The report currently being looked at */
diff --git a/src/components/TestToolMenu.js b/src/components/TestToolMenu.js
index 474e4c9bb10c..096bdfd5f97e 100644
--- a/src/components/TestToolMenu.js
+++ b/src/components/TestToolMenu.js
@@ -1,21 +1,21 @@
-import React from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import styles from '../styles/styles';
-import Switch from './Switch';
-import Text from './Text';
-import * as User from '../libs/actions/User';
-import * as Network from '../libs/actions/Network';
-import * as Session from '../libs/actions/Session';
-import ONYXKEYS from '../ONYXKEYS';
+import * as ApiUtils from '@libs/ApiUtils';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import * as Network from '@userActions/Network';
+import * as Session from '@userActions/Session';
+import * as User from '@userActions/User';
+import CONFIG from '@src/CONFIG';
+import ONYXKEYS from '@src/ONYXKEYS';
import Button from './Button';
-import TestToolRow from './TestToolRow';
import networkPropTypes from './networkPropTypes';
-import compose from '../libs/compose';
import {withNetwork} from './OnyxProvider';
-import * as ApiUtils from '../libs/ApiUtils';
-import CONFIG from '../CONFIG';
+import Switch from './Switch';
+import TestToolRow from './TestToolRow';
+import Text from './Text';
const propTypes = {
/** User object in Onyx */
diff --git a/src/components/TestToolRow.tsx b/src/components/TestToolRow.tsx
index 540c9dbc5068..149014893a83 100644
--- a/src/components/TestToolRow.tsx
+++ b/src/components/TestToolRow.tsx
@@ -1,6 +1,6 @@
import React from 'react';
import {View} from 'react-native';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
import Text from './Text';
type TestToolRowProps = {
diff --git a/src/components/TestToolsModal.js b/src/components/TestToolsModal.js
index 43a74e48df5d..3ae8223b34e7 100644
--- a/src/components/TestToolsModal.js
+++ b/src/components/TestToolsModal.js
@@ -1,13 +1,13 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import {withOnyx} from 'react-native-onyx';
+import React from 'react';
import {View} from 'react-native';
-import ONYXKEYS from '../ONYXKEYS';
+import {withOnyx} from 'react-native-onyx';
+import styles from '@styles/styles';
+import toggleTestToolsModal from '@userActions/TestTool';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import Modal from './Modal';
-import CONST from '../CONST';
-import toggleTestToolsModal from '../libs/actions/TestTool';
import TestToolMenu from './TestToolMenu';
-import styles from '../styles/styles';
const propTypes = {
/** Details about modal */
diff --git a/src/components/Text.tsx b/src/components/Text.tsx
index 60a59aae1520..80181156ee3a 100644
--- a/src/components/Text.tsx
+++ b/src/components/Text.tsx
@@ -1,62 +1,46 @@
import React, {ForwardedRef} from 'react';
// eslint-disable-next-line no-restricted-imports
-import {Text as RNText} from 'react-native';
+import {Text as RNText, TextProps as RNTextProps, StyleSheet} from 'react-native';
import type {TextStyle} from 'react-native';
-import fontFamily from '../styles/fontFamily';
-import themeColors from '../styles/themes/default';
-import variables from '../styles/variables';
+import fontFamily from '@styles/fontFamily';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
-type TextProps = {
+type TextProps = RNTextProps & {
/** The color of the text */
color?: string;
/** The size of the text */
fontSize?: number;
-
/** The alignment of the text */
textAlign?: 'left' | 'right' | 'auto' | 'center' | 'justify';
-
/** Any children to display */
children: React.ReactNode;
/** The family of the font to use */
family?: keyof typeof fontFamily;
-
- /** Any additional styles to apply */
- style?: TextStyle | TextStyle[];
};
function Text(
{color = themeColors.text, fontSize = variables.fontSizeNormal, textAlign = 'left', children = null, family = 'EXP_NEUE', style = {}, ...props}: TextProps,
ref: ForwardedRef,
) {
- // If the style prop is an array of styles, we need to mix them all together
- const mergedStyles = !Array.isArray(style)
- ? style
- : style.reduce(
- (finalStyles, s) => ({
- ...finalStyles,
- ...s,
- }),
- {},
- );
const componentStyle: TextStyle = {
color,
fontSize,
textAlign,
fontFamily: fontFamily[family],
- ...mergedStyles,
+ ...StyleSheet.flatten(style),
};
if (!componentStyle.lineHeight && componentStyle.fontSize === variables.fontSizeNormal) {
componentStyle.lineHeight = variables.fontSizeNormalHeight;
}
-
return (
diff --git a/src/components/TextInput/BaseTextInput.js b/src/components/TextInput/BaseTextInput.js
index 9bfdc79fad68..c9b1944b5b81 100644
--- a/src/components/TextInput/BaseTextInput.js
+++ b/src/components/TextInput/BaseTextInput.js
@@ -1,28 +1,28 @@
-import _ from 'underscore';
-import React, {useState, useRef, useEffect, useCallback, useMemo} from 'react';
-import {Animated, View, StyleSheet, ActivityIndicator} from 'react-native';
import Str from 'expensify-common/lib/str';
-import RNTextInput from '../RNTextInput';
-import TextInputLabel from './TextInputLabel';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {ActivityIndicator, Animated, StyleSheet, View} from 'react-native';
+import _ from 'underscore';
+import Checkbox from '@components/Checkbox';
+import FormHelpMessage from '@components/FormHelpMessage';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import RNTextInput from '@components/RNTextInput';
+import SwipeInterceptPanResponder from '@components/SwipeInterceptPanResponder';
+import Text from '@components/Text';
+import withLocalize from '@components/withLocalize';
+import * as Browser from '@libs/Browser';
+import getSecureEntryKeyboardType from '@libs/getSecureEntryKeyboardType';
+import isInputAutoFilled from '@libs/isInputAutoFilled';
+import useNativeDriver from '@libs/useNativeDriver';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import * as baseTextInputPropTypes from './baseTextInputPropTypes';
-import themeColors from '../../styles/themes/default';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import Text from '../Text';
import * as styleConst from './styleConst';
-import * as StyleUtils from '../../styles/StyleUtils';
-import variables from '../../styles/variables';
-import Checkbox from '../Checkbox';
-import getSecureEntryKeyboardType from '../../libs/getSecureEntryKeyboardType';
-import CONST from '../../CONST';
-import FormHelpMessage from '../FormHelpMessage';
-import isInputAutoFilled from '../../libs/isInputAutoFilled';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import withLocalize from '../withLocalize';
-import useNativeDriver from '../../libs/useNativeDriver';
-import * as Browser from '../../libs/Browser';
-import SwipeInterceptPanResponder from '../SwipeInterceptPanResponder';
+import TextInputLabel from './TextInputLabel';
function BaseTextInput(props) {
const initialValue = props.value || props.defaultValue || '';
diff --git a/src/components/TextInput/TextInputLabel/index.js b/src/components/TextInput/TextInputLabel/index.js
index 4267099a56ea..f777eff039bd 100644
--- a/src/components/TextInput/TextInputLabel/index.js
+++ b/src/components/TextInput/TextInputLabel/index.js
@@ -1,8 +1,8 @@
-import React, {useRef, useEffect} from 'react';
+import React, {useEffect, useRef} from 'react';
import {Animated} from 'react-native';
-import styles from '../../../styles/styles';
-import {propTypes, defaultProps} from './TextInputLabelPropTypes';
-import CONST from '../../../CONST';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes} from './TextInputLabelPropTypes';
function TextInputLabel({for: inputId, label, labelTranslateY, labelScale}) {
const labelRef = useRef(null);
diff --git a/src/components/TextInput/TextInputLabel/index.native.js b/src/components/TextInput/TextInputLabel/index.native.js
index 9b065d4c722b..51b231287b1f 100644
--- a/src/components/TextInput/TextInputLabel/index.native.js
+++ b/src/components/TextInput/TextInputLabel/index.native.js
@@ -1,8 +1,8 @@
import React, {useState} from 'react';
import {Animated} from 'react-native';
-import styles from '../../../styles/styles';
+import * as styleConst from '@components/TextInput/styleConst';
+import styles from '@styles/styles';
import * as TextInputLabelPropTypes from './TextInputLabelPropTypes';
-import * as styleConst from '../styleConst';
function TextInputLabel(props) {
const [width, setWidth] = useState(0);
diff --git a/src/components/TextInput/index.js b/src/components/TextInput/index.js
index 6cefe04e71a1..5f6164d3bc9a 100644
--- a/src/components/TextInput/index.js
+++ b/src/components/TextInput/index.js
@@ -1,12 +1,12 @@
import React, {useEffect, useRef} from 'react';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import * as styleConst from './styleConst';
+import * as Browser from '@libs/Browser';
+import DomUtils from '@libs/DomUtils';
+import Visibility from '@libs/Visibility';
+import styles from '@styles/styles';
import BaseTextInput from './BaseTextInput';
import * as baseTextInputPropTypes from './baseTextInputPropTypes';
-import DomUtils from '../../libs/DomUtils';
-import Visibility from '../../libs/Visibility';
-import * as Browser from '../../libs/Browser';
+import * as styleConst from './styleConst';
function TextInput(props) {
const textInputRef = useRef(null);
@@ -73,10 +73,14 @@ TextInput.displayName = 'TextInput';
TextInput.propTypes = baseTextInputPropTypes.propTypes;
TextInput.defaultProps = baseTextInputPropTypes.defaultProps;
-export default React.forwardRef((props, ref) => (
+const TextInputWithRef = React.forwardRef((props, ref) => (
));
+
+TextInputWithRef.displayName = 'TextInputWithRef';
+
+export default TextInputWithRef;
diff --git a/src/components/TextInput/index.native.js b/src/components/TextInput/index.native.js
index 059550855c0a..d28824a9977b 100644
--- a/src/components/TextInput/index.native.js
+++ b/src/components/TextInput/index.native.js
@@ -1,6 +1,6 @@
import React, {forwardRef, useEffect} from 'react';
import {AppState, Keyboard} from 'react-native';
-import styles from '../../styles/styles';
+import styles from '@styles/styles';
import BaseTextInput from './BaseTextInput';
import * as baseTextInputPropTypes from './baseTextInputPropTypes';
diff --git a/src/components/TextInput/styleConst.js b/src/components/TextInput/styleConst.js
index f57b3f3ca56d..7d2f3021e3be 100644
--- a/src/components/TextInput/styleConst.js
+++ b/src/components/TextInput/styleConst.js
@@ -1,4 +1,4 @@
-import variables from '../../styles/variables';
+import variables from '@styles/variables';
const ACTIVE_LABEL_TRANSLATE_Y = 4;
const ACTIVE_LABEL_SCALE = 0.8668;
diff --git a/src/components/TextInputWithCurrencySymbol/BaseTextInputWithCurrencySymbol.js b/src/components/TextInputWithCurrencySymbol/BaseTextInputWithCurrencySymbol.js
index 6dd1aacb0b09..ee7abde8c554 100644
--- a/src/components/TextInputWithCurrencySymbol/BaseTextInputWithCurrencySymbol.js
+++ b/src/components/TextInputWithCurrencySymbol/BaseTextInputWithCurrencySymbol.js
@@ -1,9 +1,9 @@
import React from 'react';
-import AmountTextInput from '../AmountTextInput';
-import CurrencySymbolButton from '../CurrencySymbolButton';
-import * as CurrencyUtils from '../../libs/CurrencyUtils';
-import useLocalize from '../../hooks/useLocalize';
-import * as MoneyRequestUtils from '../../libs/MoneyRequestUtils';
+import AmountTextInput from '@components/AmountTextInput';
+import CurrencySymbolButton from '@components/CurrencySymbolButton';
+import useLocalize from '@hooks/useLocalize';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
import * as textInputWithCurrencySymbolPropTypes from './textInputWithCurrencySymbolPropTypes';
function BaseTextInputWithCurrencySymbol(props) {
@@ -63,10 +63,14 @@ BaseTextInputWithCurrencySymbol.propTypes = textInputWithCurrencySymbolPropTypes
BaseTextInputWithCurrencySymbol.defaultProps = textInputWithCurrencySymbolPropTypes.defaultProps;
BaseTextInputWithCurrencySymbol.displayName = 'BaseTextInputWithCurrencySymbol';
-export default React.forwardRef((props, ref) => (
+const BaseTextInputWithCurrencySymbolWithRef = React.forwardRef((props, ref) => (
));
+
+BaseTextInputWithCurrencySymbolWithRef.displayName = 'BaseTextInputWithCurrencySymbolWithRef';
+
+export default BaseTextInputWithCurrencySymbolWithRef;
diff --git a/src/components/TextInputWithCurrencySymbol/index.android.js b/src/components/TextInputWithCurrencySymbol/index.android.js
index e597566d6ffd..f152cd3aa54f 100644
--- a/src/components/TextInputWithCurrencySymbol/index.android.js
+++ b/src/components/TextInputWithCurrencySymbol/index.android.js
@@ -1,4 +1,4 @@
-import React, {useState, useEffect} from 'react';
+import React, {useEffect, useState} from 'react';
import _ from 'underscore';
import BaseTextInputWithCurrencySymbol from './BaseTextInputWithCurrencySymbol';
import * as textInputWithCurrencySymbolPropTypes from './textInputWithCurrencySymbolPropTypes';
@@ -30,10 +30,14 @@ TextInputWithCurrencySymbol.propTypes = textInputWithCurrencySymbolPropTypes.pro
TextInputWithCurrencySymbol.defaultProps = textInputWithCurrencySymbolPropTypes.defaultProps;
TextInputWithCurrencySymbol.displayName = 'TextInputWithCurrencySymbol';
-export default React.forwardRef((props, ref) => (
+const TextInputWithCurrencySymbolWithRef = React.forwardRef((props, ref) => (
));
+
+TextInputWithCurrencySymbolWithRef.displayName = 'TextInputWithCurrencySymbolWithRef';
+
+export default TextInputWithCurrencySymbolWithRef;
diff --git a/src/components/TextInputWithCurrencySymbol/index.js b/src/components/TextInputWithCurrencySymbol/index.js
index f70134a2e0eb..2102882a74a3 100644
--- a/src/components/TextInputWithCurrencySymbol/index.js
+++ b/src/components/TextInputWithCurrencySymbol/index.js
@@ -17,10 +17,14 @@ TextInputWithCurrencySymbol.propTypes = textInputWithCurrencySymbolPropTypes.pro
TextInputWithCurrencySymbol.defaultProps = textInputWithCurrencySymbolPropTypes.defaultProps;
TextInputWithCurrencySymbol.displayName = 'TextInputWithCurrencySymbol';
-export default React.forwardRef((props, ref) => (
+const TextInputWithCurrencySymbolWithRef = React.forwardRef((props, ref) => (
));
+
+TextInputWithCurrencySymbolWithRef.displayName = 'TextInputWithCurrencySymbolWithRef';
+
+export default TextInputWithCurrencySymbolWithRef;
diff --git a/src/components/TextInputWithCurrencySymbol/textInputWithCurrencySymbolPropTypes.js b/src/components/TextInputWithCurrencySymbol/textInputWithCurrencySymbolPropTypes.js
index 4e891029e71d..656561c14b14 100644
--- a/src/components/TextInputWithCurrencySymbol/textInputWithCurrencySymbolPropTypes.js
+++ b/src/components/TextInputWithCurrencySymbol/textInputWithCurrencySymbolPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import refPropTypes from '../refPropTypes';
+import refPropTypes from '@components/refPropTypes';
const propTypes = {
/** A ref to forward to amount text input */
diff --git a/src/components/TextLink.js b/src/components/TextLink.js
index 233aaf50644e..79f3d43a7743 100644
--- a/src/components/TextLink.js
+++ b/src/components/TextLink.js
@@ -1,12 +1,12 @@
-import _ from 'underscore';
-import React from 'react';
import PropTypes from 'prop-types';
-import Text from './Text';
-import styles from '../styles/styles';
-import stylePropTypes from '../styles/stylePropTypes';
-import CONST from '../CONST';
-import * as Link from '../libs/actions/Link';
+import React from 'react';
+import _ from 'underscore';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import CONST from '@src/CONST';
import refPropTypes from './refPropTypes';
+import Text from './Text';
const propTypes = {
/** Link to open in new tab */
@@ -84,10 +84,15 @@ function TextLink(props) {
TextLink.defaultProps = defaultProps;
TextLink.propTypes = propTypes;
TextLink.displayName = 'TextLink';
-export default React.forwardRef((props, ref) => (
+
+const TextLinkWithRef = React.forwardRef((props, ref) => (
));
+
+TextLinkWithRef.displayName = 'TextLinkWithRef';
+
+export default TextLinkWithRef;
diff --git a/src/components/TextPill.js b/src/components/TextPill.js
index a8a4f35b64fb..81bb0ca1e037 100644
--- a/src/components/TextPill.js
+++ b/src/components/TextPill.js
@@ -1,9 +1,9 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import Text from './Text';
-import styles from '../styles/styles';
-import stylePropTypes from '../styles/stylePropTypes';
-import * as StyleUtils from '../styles/StyleUtils';
const propTypes = {
text: PropTypes.string.isRequired,
diff --git a/src/components/TextWithEllipsis/index.js b/src/components/TextWithEllipsis/index.js
index 1734e24b03b6..8c2cd0dd9557 100644
--- a/src/components/TextWithEllipsis/index.js
+++ b/src/components/TextWithEllipsis/index.js
@@ -1,10 +1,10 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
-import Text from '../Text';
-import styles from '../../styles/styles';
-import stylePropTypes from '../../styles/stylePropTypes';
-import * as StyleUtils from '../../styles/StyleUtils';
+import Text from '@components/Text';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
const propTypes = {
/** Leading text before the ellipsis */
diff --git a/src/components/ThreeDotsMenu/index.js b/src/components/ThreeDotsMenu/index.js
index 3aac98fa1275..973aa7e5e189 100644
--- a/src/components/ThreeDotsMenu/index.js
+++ b/src/components/ThreeDotsMenu/index.js
@@ -1,17 +1,17 @@
-import React, {useState, useRef} from 'react';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useRef, useState} from 'react';
+import {View} from 'react-native';
import _ from 'underscore';
-import Icon from '../Icon';
-import PopoverMenu from '../PopoverMenu';
-import styles from '../../styles/styles';
-import useLocalize from '../../hooks/useLocalize';
-import Tooltip from '../Tooltip/PopoverAnchorTooltip';
-import * as Expensicons from '../Icon/Expensicons';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PopoverMenu from '@components/PopoverMenu';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
+import useLocalize from '@hooks/useLocalize';
+import * as Browser from '@libs/Browser';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import ThreeDotsMenuItemPropTypes from './ThreeDotsMenuItemPropTypes';
-import CONST from '../../CONST';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import * as Browser from '../../libs/Browser';
const propTypes = {
/** Tooltip for the popup icon */
@@ -50,12 +50,16 @@ const propTypes = {
/** Whether the popover menu should overlay the current view */
shouldOverlay: PropTypes.bool,
+ /** Whether the menu is disabled */
+ disabled: PropTypes.bool,
+
/** Should we announce the Modal visibility changes? */
shouldSetModalVisibility: PropTypes.bool,
};
const defaultProps = {
iconTooltip: 'common.more',
+ disabled: false,
iconFill: undefined,
iconStyles: [],
icon: Expensicons.ThreeDots,
@@ -68,7 +72,7 @@ const defaultProps = {
shouldSetModalVisibility: true,
};
-function ThreeDotsMenu({iconTooltip, icon, iconFill, iconStyles, onIconPress, menuItems, anchorPosition, anchorAlignment, shouldOverlay, shouldSetModalVisibility}) {
+function ThreeDotsMenu({iconTooltip, icon, iconFill, iconStyles, onIconPress, menuItems, anchorPosition, anchorAlignment, shouldOverlay, shouldSetModalVisibility, disabled}) {
const [isPopupMenuVisible, setPopupMenuVisible] = useState(false);
const buttonRef = useRef(null);
const {translate} = useLocalize();
@@ -96,6 +100,7 @@ function ThreeDotsMenu({iconTooltip, icon, iconFill, iconStyles, onIconPress, me
onIconPress();
}
}}
+ disabled={disabled}
onMouseDown={(e) => {
/* Keep the focus state on mWeb like we did on the native apps. */
if (!Browser.isMobile()) {
diff --git a/src/components/ThumbnailImage.js b/src/components/ThumbnailImage.js
index 983f806bb2e2..bbd5e27accc1 100644
--- a/src/components/ThumbnailImage.js
+++ b/src/components/ThumbnailImage.js
@@ -1,12 +1,12 @@
import lodashClamp from 'lodash/clamp';
-import React, {useCallback, useState} from 'react';
-import {View, Dimensions} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback, useState} from 'react';
+import {Dimensions, View} from 'react-native';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import ImageWithSizeCalculation from './ImageWithSizeCalculation';
-import styles from '../styles/styles';
-import * as StyleUtils from '../styles/StyleUtils';
-import * as DeviceCapabilities from '../libs/DeviceCapabilities';
-import useWindowDimensions from '../hooks/useWindowDimensions';
const propTypes = {
/** Source URL for the preview image */
diff --git a/src/components/Tooltip/BaseTooltip.js b/src/components/Tooltip/BaseTooltip.js
index 7ef80c552980..3eb905e7a3e5 100644
--- a/src/components/Tooltip/BaseTooltip.js
+++ b/src/components/Tooltip/BaseTooltip.js
@@ -1,16 +1,16 @@
-import _ from 'underscore';
-import React, {memo, useCallback, useEffect, useRef, useState} from 'react';
-import {Animated} from 'react-native';
import {BoundsObserver} from '@react-ng/bounds-observer';
import Str from 'expensify-common/lib/str';
-import TooltipRenderedOnPageBody from './TooltipRenderedOnPageBody';
-import Hoverable from '../Hoverable';
+import React, {memo, useCallback, useEffect, useRef, useState} from 'react';
+import {Animated} from 'react-native';
+import _ from 'underscore';
+import Hoverable from '@components/Hoverable';
+import useLocalize from '@hooks/useLocalize';
+import usePrevious from '@hooks/usePrevious';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import * as tooltipPropTypes from './tooltipPropTypes';
+import TooltipRenderedOnPageBody from './TooltipRenderedOnPageBody';
import TooltipSense from './TooltipSense';
-import * as DeviceCapabilities from '../../libs/DeviceCapabilities';
-import usePrevious from '../../hooks/usePrevious';
-import useLocalize from '../../hooks/useLocalize';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
const hasHoverSupport = DeviceCapabilities.hasHoverSupport();
diff --git a/src/components/Tooltip/PopoverAnchorTooltip.js b/src/components/Tooltip/PopoverAnchorTooltip.js
index bca49ac9b7bc..6123be56544c 100644
--- a/src/components/Tooltip/PopoverAnchorTooltip.js
+++ b/src/components/Tooltip/PopoverAnchorTooltip.js
@@ -1,8 +1,8 @@
-import React, {useContext, useRef, useMemo} from 'react';
import PropTypes from 'prop-types';
-import {propTypes as tooltipPropTypes, defaultProps as tooltipDefaultProps} from './tooltipPropTypes';
+import React, {useContext, useMemo, useRef} from 'react';
+import {PopoverContext} from '@components/PopoverProvider';
import BaseTooltip from './BaseTooltip';
-import {PopoverContext} from '../PopoverProvider';
+import {defaultProps as tooltipDefaultProps, propTypes as tooltipPropTypes} from './tooltipPropTypes';
const propTypes = {
...tooltipPropTypes,
diff --git a/src/components/Tooltip/TooltipRenderedOnPageBody.js b/src/components/Tooltip/TooltipRenderedOnPageBody.js
index f61ecaee1059..69d06775ae2a 100644
--- a/src/components/Tooltip/TooltipRenderedOnPageBody.js
+++ b/src/components/Tooltip/TooltipRenderedOnPageBody.js
@@ -1,10 +1,10 @@
-import React, {useLayoutEffect, useEffect, useState, useRef, useMemo} from 'react';
import PropTypes from 'prop-types';
-import {Animated, View} from 'react-native';
+import React, {useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react';
import ReactDOM from 'react-dom';
-import getTooltipStyles from '../../styles/getTooltipStyles';
-import Text from '../Text';
-import Log from '../../libs/Log';
+import {Animated, View} from 'react-native';
+import Text from '@components/Text';
+import Log from '@libs/Log';
+import getTooltipStyles from '@styles/getTooltipStyles';
const propTypes = {
/** Window width */
diff --git a/src/components/Tooltip/TooltipSense.js b/src/components/Tooltip/TooltipSense.js
index 76cd25294497..0e551e687cf3 100644
--- a/src/components/Tooltip/TooltipSense.js
+++ b/src/components/Tooltip/TooltipSense.js
@@ -1,5 +1,5 @@
import _ from 'underscore';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
let active = false;
diff --git a/src/components/Tooltip/index.js b/src/components/Tooltip/index.js
index 2e6789ec73f6..19a607220e1c 100644
--- a/src/components/Tooltip/index.js
+++ b/src/components/Tooltip/index.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import {propTypes as tooltipPropTypes, defaultProps as tooltipDefaultProps} from './tooltipPropTypes';
+import React from 'react';
import BaseTooltip from './BaseTooltip';
+import {defaultProps as tooltipDefaultProps, propTypes as tooltipPropTypes} from './tooltipPropTypes';
const propTypes = {
...tooltipPropTypes,
diff --git a/src/components/Tooltip/tooltipPropTypes.js b/src/components/Tooltip/tooltipPropTypes.js
index 684a102e0339..21df0df07f0d 100644
--- a/src/components/Tooltip/tooltipPropTypes.js
+++ b/src/components/Tooltip/tooltipPropTypes.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
-import refPropTypes from '../refPropTypes';
-import variables from '../../styles/variables';
-import CONST from '../../CONST';
+import refPropTypes from '@components/refPropTypes';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
const propTypes = {
/** The text to display in the tooltip. If text is ommitted, only children will be rendered. */
diff --git a/src/components/UnorderedList.js b/src/components/UnorderedList.js
index 4500d9fc3538..de8cb4abd7f8 100644
--- a/src/components/UnorderedList.js
+++ b/src/components/UnorderedList.js
@@ -1,9 +1,9 @@
+import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'underscore';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
+import _ from 'underscore';
+import styles from '@styles/styles';
import Text from './Text';
-import styles from '../styles/styles';
const propTypes = {
/** An array of strings to display as an unordered list */
diff --git a/src/components/UnreadActionIndicator.js b/src/components/UnreadActionIndicator.js
index ff1090640570..4ba4ded97820 100755
--- a/src/components/UnreadActionIndicator.js
+++ b/src/components/UnreadActionIndicator.js
@@ -1,8 +1,8 @@
import React from 'react';
import {View} from 'react-native';
-import styles from '../styles/styles';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import Text from './Text';
-import CONST from '../CONST';
import withLocalize, {withLocalizePropTypes} from './withLocalize';
function UnreadActionIndicator(props) {
diff --git a/src/components/UpdateAppModal/BaseUpdateAppModal.js b/src/components/UpdateAppModal/BaseUpdateAppModal.js
index 7dfa0e7d3a82..07b446172286 100755
--- a/src/components/UpdateAppModal/BaseUpdateAppModal.js
+++ b/src/components/UpdateAppModal/BaseUpdateAppModal.js
@@ -1,7 +1,7 @@
-import React, {useState, memo} from 'react';
-import {propTypes, defaultProps} from './updateAppModalPropTypes';
-import ConfirmModal from '../ConfirmModal';
-import withLocalize from '../withLocalize';
+import React, {memo, useState} from 'react';
+import ConfirmModal from '@components/ConfirmModal';
+import withLocalize from '@components/withLocalize';
+import {defaultProps, propTypes} from './updateAppModalPropTypes';
function BaseUpdateAppModal({translate, onSubmit}) {
const [isModalOpen, setIsModalOpen] = useState(true);
diff --git a/src/components/UpdateAppModal/index.desktop.js b/src/components/UpdateAppModal/index.desktop.js
index 424b7a616e39..397ce2c75ea3 100644
--- a/src/components/UpdateAppModal/index.desktop.js
+++ b/src/components/UpdateAppModal/index.desktop.js
@@ -1,7 +1,7 @@
import React from 'react';
+import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
import BaseUpdateAppModal from './BaseUpdateAppModal';
import {propTypes} from './updateAppModalPropTypes';
-import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
function UpdateAppModal(props) {
const updateApp = () => {
diff --git a/src/components/UserDetailsTooltip/BaseUserDetailsTooltip.web.js b/src/components/UserDetailsTooltip/BaseUserDetailsTooltip.web.js
index 5f124cb21467..871173d01b56 100644
--- a/src/components/UserDetailsTooltip/BaseUserDetailsTooltip.web.js
+++ b/src/components/UserDetailsTooltip/BaseUserDetailsTooltip.web.js
@@ -1,18 +1,18 @@
-import React, {useCallback} from 'react';
-import {View, Text} from 'react-native';
-import {withOnyx} from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
+import React, {useCallback} from 'react';
+import {Text, View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import Avatar from '../Avatar';
-import Tooltip from '../Tooltip';
-import {propTypes, defaultProps} from './userDetailsTooltipPropTypes';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as UserUtils from '../../libs/UserUtils';
-import CONST from '../../CONST';
-import * as LocalePhoneNumber from '../../libs/LocalePhoneNumber';
-import useLocalize from '../../hooks/useLocalize';
+import Avatar from '@components/Avatar';
+import Tooltip from '@components/Tooltip';
+import useLocalize from '@hooks/useLocalize';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps, propTypes} from './userDetailsTooltipPropTypes';
function BaseUserDetailsTooltip(props) {
const {translate} = useLocalize();
diff --git a/src/components/UserDetailsTooltip/index.js b/src/components/UserDetailsTooltip/index.js
index 86778e4a1019..ea5cd4337071 100644
--- a/src/components/UserDetailsTooltip/index.js
+++ b/src/components/UserDetailsTooltip/index.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import {propTypes as userDetailsTooltipPropTypes, defaultProps as userDetailsTooltipDefaultProps} from './userDetailsTooltipPropTypes';
+import React from 'react';
import BaseUserDetailsTooltip from './BaseUserDetailsTooltip';
+import {defaultProps as userDetailsTooltipDefaultProps, propTypes as userDetailsTooltipPropTypes} from './userDetailsTooltipPropTypes';
const propTypes = {
...userDetailsTooltipPropTypes,
diff --git a/src/components/UserDetailsTooltip/userDetailsTooltipPropTypes.js b/src/components/UserDetailsTooltip/userDetailsTooltipPropTypes.js
index f311ed0d18df..538e9ad5348f 100644
--- a/src/components/UserDetailsTooltip/userDetailsTooltipPropTypes.js
+++ b/src/components/UserDetailsTooltip/userDetailsTooltipPropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import personalDetailsPropType from '../../pages/personalDetailsPropType';
-import avatarPropTypes from '../avatarPropTypes';
+import avatarPropTypes from '@components/avatarPropTypes';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
const propTypes = {
/** User's Account ID */
diff --git a/src/components/ValidateCode/ExpiredValidateCodeModal.js b/src/components/ValidateCode/ExpiredValidateCodeModal.js
index e31e0772a8c5..f75cc3f19d49 100644
--- a/src/components/ValidateCode/ExpiredValidateCodeModal.js
+++ b/src/components/ValidateCode/ExpiredValidateCodeModal.js
@@ -1,13 +1,13 @@
import React from 'react';
import {View} from 'react-native';
-import themeColors from '../../styles/themes/default';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import Text from '../Text';
-import * as Expensicons from '../Icon/Expensicons';
-import * as Illustrations from '../Icon/Illustrations';
-import variables from '../../styles/variables';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/components/ValidateCode/JustSignedInModal.js b/src/components/ValidateCode/JustSignedInModal.js
index e96505470eba..dd6085646120 100644
--- a/src/components/ValidateCode/JustSignedInModal.js
+++ b/src/components/ValidateCode/JustSignedInModal.js
@@ -1,14 +1,14 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
-import themeColors from '../../styles/themes/default';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import Text from '../Text';
-import * as Expensicons from '../Icon/Expensicons';
-import * as Illustrations from '../Icon/Illustrations';
-import variables from '../../styles/variables';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/components/ValidateCode/ValidateCodeModal.js b/src/components/ValidateCode/ValidateCodeModal.js
index ceebc54a47af..173467d16b14 100644
--- a/src/components/ValidateCode/ValidateCodeModal.js
+++ b/src/components/ValidateCode/ValidateCodeModal.js
@@ -1,20 +1,20 @@
-import React, {useCallback} from 'react';
-import PropTypes from 'prop-types';
-import {compose} from 'underscore';
-import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
import {View} from 'react-native';
-import themeColors from '../../styles/themes/default';
-import styles from '../../styles/styles';
-import Icon from '../Icon';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import Text from '../Text';
-import * as Expensicons from '../Icon/Expensicons';
-import * as Illustrations from '../Icon/Illustrations';
-import variables from '../../styles/variables';
-import TextLink from '../TextLink';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as Session from '../../libs/actions/Session';
+import {withOnyx} from 'react-native-onyx';
+import {compose} from 'underscore';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Code to display. */
diff --git a/src/components/ValuePicker/ValueSelectorModal.js b/src/components/ValuePicker/ValueSelectorModal.js
index 23aac4839d2a..0a524a324959 100644
--- a/src/components/ValuePicker/ValueSelectorModal.js
+++ b/src/components/ValuePicker/ValueSelectorModal.js
@@ -1,12 +1,12 @@
-import React, {useState, useEffect} from 'react';
-import PropTypes from 'prop-types';
import _ from 'lodash';
-import CONST from '../../CONST';
-import HeaderWithBackButton from '../HeaderWithBackButton';
-import SelectionList from '../SelectionList';
-import Modal from '../Modal';
-import ScreenWrapper from '../ScreenWrapper';
-import styles from '../../styles/styles';
+import PropTypes from 'prop-types';
+import React, {useEffect, useState} from 'react';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Modal from '@components/Modal';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether the modal is visible */
diff --git a/src/components/ValuePicker/index.js b/src/components/ValuePicker/index.js
index 161fbbfadb8b..e9ec200b7a7d 100644
--- a/src/components/ValuePicker/index.js
+++ b/src/components/ValuePicker/index.js
@@ -1,12 +1,14 @@
+import _ from 'lodash';
+import PropTypes from 'prop-types';
import React, {useState} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import _ from 'lodash';
-import styles from '../../styles/styles';
-import MenuItemWithTopDescription from '../MenuItemWithTopDescription';
+import FormHelpMessage from '@components/FormHelpMessage';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import refPropTypes from '@components/refPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
import ValueSelectorModal from './ValueSelectorModal';
-import FormHelpMessage from '../FormHelpMessage';
-import refPropTypes from '../refPropTypes';
const propTypes = {
/** Form Error description */
@@ -59,7 +61,7 @@ function ValuePicker({value, label, items, placeholder, errorText, onInputChange
hidePickerModal();
};
- const descStyle = value.length === 0 ? styles.textNormal : null;
+ const descStyle = value.length === 0 ? StyleUtils.getFontSizeStyle(variables.fontSizeLabel) : null;
const selectedItem = _.find(items, {value});
const selectedLabel = selectedItem ? selectedItem.label : '';
@@ -93,10 +95,14 @@ ValuePicker.propTypes = propTypes;
ValuePicker.defaultProps = defaultProps;
ValuePicker.displayName = 'ValuePicker';
-export default React.forwardRef((props, ref) => (
+const ValuePickerWithRef = React.forwardRef((props, ref) => (
));
+
+ValuePickerWithRef.displayName = 'ValuePickerWithRef';
+
+export default ValuePickerWithRef;
diff --git a/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js b/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js
index ed1b71c8fb0f..ceb10de0f909 100755
--- a/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js
+++ b/src/components/VideoChatButtonAndMenu/BaseVideoChatButtonAndMenu.js
@@ -1,24 +1,24 @@
-import _ from 'underscore';
-import React, {useState, useRef, useEffect, useCallback} from 'react';
-import {View, Dimensions} from 'react-native';
import PropTypes from 'prop-types';
-import Icon from '../Icon';
-import * as Expensicons from '../Icon/Expensicons';
-import Popover from '../Popover';
-import MenuItem from '../MenuItem';
-import ZoomIcon from '../../../assets/images/zoom-icon.svg';
-import GoogleMeetIcon from '../../../assets/images/google-meet.svg';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
-import withLocalize, {withLocalizePropTypes} from '../withLocalize';
-import compose from '../../libs/compose';
-import Tooltip from '../Tooltip/PopoverAnchorTooltip';
-import {propTypes as videoChatButtonAndMenuPropTypes, defaultProps} from './videoChatButtonAndMenuPropTypes';
-import * as Session from '../../libs/actions/Session';
-import PressableWithoutFeedback from '../Pressable/PressableWithoutFeedback';
-import * as Link from '../../libs/actions/Link';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
+import {Dimensions, View} from 'react-native';
+import _ from 'underscore';
+import GoogleMeetIcon from '@assets/images/google-meet.svg';
+import ZoomIcon from '@assets/images/zoom-icon.svg';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import Popover from '@components/Popover';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as Link from '@userActions/Link';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import {defaultProps, propTypes as videoChatButtonAndMenuPropTypes} from './videoChatButtonAndMenuPropTypes';
const propTypes = {
/** Link to open when user wants to create a new google meet meeting */
diff --git a/src/components/VideoChatButtonAndMenu/index.android.js b/src/components/VideoChatButtonAndMenu/index.android.js
index 53f43b73d600..fe19a530aa95 100644
--- a/src/components/VideoChatButtonAndMenu/index.android.js
+++ b/src/components/VideoChatButtonAndMenu/index.android.js
@@ -1,7 +1,7 @@
import React from 'react';
-import CONST from '../../CONST';
-import {propTypes, defaultProps} from './videoChatButtonAndMenuPropTypes';
+import CONST from '@src/CONST';
import BaseVideoChatButtonAndMenu from './BaseVideoChatButtonAndMenu';
+import {defaultProps, propTypes} from './videoChatButtonAndMenuPropTypes';
// On Android creating a new google meet meeting requires the CALL_PHONE permission in some cases
// so we're just opening the google meet app instead, more details:
diff --git a/src/components/VideoChatButtonAndMenu/index.js b/src/components/VideoChatButtonAndMenu/index.js
index bf3be904103a..f3f657066e54 100644
--- a/src/components/VideoChatButtonAndMenu/index.js
+++ b/src/components/VideoChatButtonAndMenu/index.js
@@ -1,7 +1,7 @@
import React from 'react';
-import CONST from '../../CONST';
-import {propTypes, defaultProps} from './videoChatButtonAndMenuPropTypes';
+import CONST from '@src/CONST';
import BaseVideoChatButtonAndMenu from './BaseVideoChatButtonAndMenu';
+import {defaultProps, propTypes} from './videoChatButtonAndMenuPropTypes';
function VideoChatButtonAndMenu(props) {
return (
diff --git a/src/components/WalletSection.js b/src/components/WalletSection.js
index ec8a1680937c..d79d2be0ddc9 100644
--- a/src/components/WalletSection.js
+++ b/src/components/WalletSection.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import React from 'react';
+import styles from '@styles/styles';
import Section from './Section';
-import styles from '../styles/styles';
const propTypes = {
/** Contents to display inside the section */
diff --git a/src/components/WalletStatementModal/index.js b/src/components/WalletStatementModal/index.js
index b4d87bf4e0e4..59508f8057ab 100644
--- a/src/components/WalletStatementModal/index.js
+++ b/src/components/WalletStatementModal/index.js
@@ -1,18 +1,18 @@
-import React, {useState} from 'react';
-import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import React, {useState} from 'react';
import {View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import compose from '../../libs/compose';
-import withLocalize from '../withLocalize';
-import ONYXKEYS from '../../ONYXKEYS';
-import {walletStatementPropTypes, walletStatementDefaultProps} from './WalletStatementModalPropTypes';
-import styles from '../../styles/styles';
-import FullScreenLoadingIndicator from '../FullscreenLoadingIndicator';
-import ROUTES from '../../ROUTES';
-import Navigation from '../../libs/Navigation/Navigation';
-import * as Report from '../../libs/actions/Report';
-import CONST from '../../CONST';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import withLocalize from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {walletStatementDefaultProps, walletStatementPropTypes} from './WalletStatementModalPropTypes';
function WalletStatementModal({statementPageURL, session}) {
const [isLoading, setIsLoading] = useState(true);
diff --git a/src/components/WalletStatementModal/index.native.js b/src/components/WalletStatementModal/index.native.js
index 38d1f90af00d..9c2aea8e8ec4 100644
--- a/src/components/WalletStatementModal/index.native.js
+++ b/src/components/WalletStatementModal/index.native.js
@@ -1,15 +1,15 @@
-import React, {useCallback, useRef} from 'react';
-import {WebView} from 'react-native-webview';
import lodashGet from 'lodash/get';
+import React, {useCallback, useRef} from 'react';
import {withOnyx} from 'react-native-onyx';
+import {WebView} from 'react-native-webview';
import _ from 'underscore';
-import {walletStatementPropTypes, walletStatementDefaultProps} from './WalletStatementModalPropTypes';
-import FullScreenLoadingIndicator from '../FullscreenLoadingIndicator';
-import * as Report from '../../libs/actions/Report';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Navigation from '@libs/Navigation/Navigation';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {walletStatementDefaultProps, walletStatementPropTypes} from './WalletStatementModalPropTypes';
const IOU_ROUTES = [ROUTES.IOU_REQUEST, ROUTES.IOU_SEND];
const renderLoading = () => ;
diff --git a/src/components/ZeroWidthView/index.js b/src/components/ZeroWidthView/index.js
index 6c3809a40a04..58b2dfa039ef 100644
--- a/src/components/ZeroWidthView/index.js
+++ b/src/components/ZeroWidthView/index.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import * as EmojiUtils from '../../libs/EmojiUtils';
-import * as Browser from '../../libs/Browser';
-import Text from '../Text';
+import React from 'react';
+import Text from '@components/Text';
+import * as Browser from '@libs/Browser';
+import * as EmojiUtils from '@libs/EmojiUtils';
const propTypes = {
/** If this is the Concierge chat, we'll open the modal for requesting a setup call instead of showing popover menu */
diff --git a/src/components/avatarPropTypes.js b/src/components/avatarPropTypes.js
index 915eac995fcb..9ecea0fad778 100644
--- a/src/components/avatarPropTypes.js
+++ b/src/components/avatarPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
export default PropTypes.shape({
source: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
diff --git a/src/components/createOnyxContext.tsx b/src/components/createOnyxContext.tsx
index a0ac5942b098..f7b2d6cbf297 100644
--- a/src/components/createOnyxContext.tsx
+++ b/src/components/createOnyxContext.tsx
@@ -1,9 +1,9 @@
-import React, {ComponentType, ForwardRefExoticComponent, ForwardedRef, PropsWithoutRef, ReactNode, RefAttributes, createContext, forwardRef, useContext} from 'react';
-import {withOnyx} from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
-import {OnyxCollectionKey, OnyxKey, OnyxKeyValue, OnyxValues} from '../ONYXKEYS';
-import ChildrenProps from '../types/utils/ChildrenProps';
+import React, {ComponentType, createContext, ForwardedRef, forwardRef, ForwardRefExoticComponent, PropsWithoutRef, ReactNode, RefAttributes, useContext} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import {OnyxCollectionKey, OnyxKey, OnyxKeyValue, OnyxValues} from '@src/ONYXKEYS';
+import ChildrenProps from '@src/types/utils/ChildrenProps';
type OnyxKeys = (OnyxKey | OnyxCollectionKey) & keyof OnyxValues;
diff --git a/src/components/menuItemPropTypes.js b/src/components/menuItemPropTypes.js
index a5b5b3a8eba8..d4b12b9cf479 100644
--- a/src/components/menuItemPropTypes.js
+++ b/src/components/menuItemPropTypes.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
import _ from 'underscore';
-import CONST from '../CONST';
-import stylePropTypes from '../styles/stylePropTypes';
+import stylePropTypes from '@styles/stylePropTypes';
+import CONST from '@src/CONST';
import avatarPropTypes from './avatarPropTypes';
import refPropTypes from './refPropTypes';
@@ -154,6 +154,9 @@ const propTypes = {
/** Should render component on the right */
shouldShowRightComponent: PropTypes.bool,
+ /** Array of objects that map display names to their corresponding tooltip */
+ titleWithTooltips: PropTypes.arrayOf(PropTypes.object),
+
/** Should check anonymous user in onPress function */
shouldCheckActionAllowedOnPress: PropTypes.bool,
};
diff --git a/src/components/optionPropTypes.js b/src/components/optionPropTypes.js
index 709298036f07..d5ef485b8276 100644
--- a/src/components/optionPropTypes.js
+++ b/src/components/optionPropTypes.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
-import CONST from '../CONST';
-import participantPropTypes from './participantPropTypes';
+import CONST from '@src/CONST';
import avatarPropTypes from './avatarPropTypes';
+import participantPropTypes from './participantPropTypes';
export default PropTypes.shape({
// Text to display
diff --git a/src/components/transactionPropTypes.js b/src/components/transactionPropTypes.js
index bc0a10025ba8..049fe60630e5 100644
--- a/src/components/transactionPropTypes.js
+++ b/src/components/transactionPropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import _ from 'underscore';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
export default PropTypes.shape({
/** The transaction id */
@@ -45,6 +45,9 @@ export default PropTypes.shape({
/** The address of the waypoint */
address: PropTypes.string,
+
+ /** The name of the waypoint */
+ name: PropTypes.string,
}),
}),
diff --git a/src/components/withAnimatedRef.js b/src/components/withAnimatedRef.js
deleted file mode 100644
index 71ef130b9ce7..000000000000
--- a/src/components/withAnimatedRef.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import React from 'react';
-import {useAnimatedRef} from 'react-native-reanimated';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
-import refPropTypes from './refPropTypes';
-
-export default function withAnimatedRef(WrappedComponent) {
- function WithAnimatedRef(props) {
- const animatedRef = useAnimatedRef();
- return (
-
- );
- }
- WithAnimatedRef.displayName = `withAnimatedRef(${getComponentDisplayName(WrappedComponent)})`;
- WithAnimatedRef.propTypes = {
- forwardedRef: refPropTypes,
- };
- WithAnimatedRef.defaultProps = {
- forwardedRef: undefined,
- };
-
- return React.forwardRef((props, ref) => (
-
- ));
-}
diff --git a/src/components/withCurrentReportID.js b/src/components/withCurrentReportID.js
index 18f716981e65..ab1b5abc2395 100644
--- a/src/components/withCurrentReportID.js
+++ b/src/components/withCurrentReportID.js
@@ -1,8 +1,7 @@
-import React, {createContext, forwardRef, useCallback, useState, useMemo} from 'react';
import PropTypes from 'prop-types';
-
-import getComponentDisplayName from '../libs/getComponentDisplayName';
-import Navigation from '../libs/Navigation/Navigation';
+import React, {createContext, forwardRef, useCallback, useMemo, useState} from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import Navigation from '@libs/Navigation/Navigation';
const CurrentReportIDContext = createContext(null);
diff --git a/src/components/withCurrentUserPersonalDetails.tsx b/src/components/withCurrentUserPersonalDetails.tsx
index e1472f280f17..ed580b4dbe4a 100644
--- a/src/components/withCurrentUserPersonalDetails.tsx
+++ b/src/components/withCurrentUserPersonalDetails.tsx
@@ -1,9 +1,9 @@
-import React, {ComponentType, RefAttributes, ForwardedRef, useMemo} from 'react';
+import React, {ComponentType, ForwardedRef, RefAttributes, useMemo} from 'react';
import {OnyxEntry, withOnyx} from 'react-native-onyx';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
-import ONYXKEYS from '../ONYXKEYS';
-import personalDetailsPropType from '../pages/personalDetailsPropType';
-import type {PersonalDetails, Session} from '../types/onyx';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import ONYXKEYS from '@src/ONYXKEYS';
+import type {PersonalDetails, Session} from '@src/types/onyx';
type CurrentUserPersonalDetails = PersonalDetails | Record;
diff --git a/src/components/withEnvironment.js b/src/components/withEnvironment.js
deleted file mode 100644
index 3aa9b86e82c8..000000000000
--- a/src/components/withEnvironment.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import React, {createContext, useState, useEffect, forwardRef, useContext, useMemo} from 'react';
-import PropTypes from 'prop-types';
-import * as Environment from '../libs/Environment/Environment';
-import CONST from '../CONST';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
-
-const EnvironmentContext = createContext(null);
-
-const environmentPropTypes = {
- /** The string value representing the current environment */
- environment: PropTypes.string.isRequired,
-
- /** The string value representing the URL of the current environment */
- environmentURL: PropTypes.string.isRequired,
-};
-
-function EnvironmentProvider({children}) {
- const [environment, setEnvironment] = useState(CONST.ENVIRONMENT.PRODUCTION);
- const [environmentURL, setEnvironmentURL] = useState(CONST.NEW_EXPENSIFY_URL);
-
- useEffect(() => {
- Environment.getEnvironment().then(setEnvironment);
- Environment.getEnvironmentURL().then(setEnvironmentURL);
- }, []);
-
- const contextValue = useMemo(
- () => ({
- environment,
- environmentURL,
- }),
- [environment, environmentURL],
- );
-
- return {children} ;
-}
-
-EnvironmentProvider.displayName = 'EnvironmentProvider';
-EnvironmentProvider.propTypes = {
- /** Actual content wrapped by this component */
- children: PropTypes.node.isRequired,
-};
-
-export default function withEnvironment(WrappedComponent) {
- const WithEnvironment = forwardRef((props, ref) => {
- const {environment, environmentURL} = useContext(EnvironmentContext);
- return (
-
- );
- });
-
- WithEnvironment.displayName = `withEnvironment(${getComponentDisplayName(WrappedComponent)})`;
-
- return WithEnvironment;
-}
-
-export {EnvironmentContext, environmentPropTypes, EnvironmentProvider};
diff --git a/src/components/withEnvironment.tsx b/src/components/withEnvironment.tsx
new file mode 100644
index 000000000000..1bfc147f0db3
--- /dev/null
+++ b/src/components/withEnvironment.tsx
@@ -0,0 +1,68 @@
+import React, {ComponentType, createContext, ForwardedRef, forwardRef, ReactElement, ReactNode, RefAttributes, useContext, useEffect, useMemo, useState} from 'react';
+import {ValueOf} from 'type-fest';
+import * as Environment from '@libs/Environment/Environment';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import CONST from '@src/CONST';
+
+type EnvironmentProviderProps = {
+ /** Actual content wrapped by this component */
+ children: ReactNode;
+};
+
+type EnvironmentValue = ValueOf;
+
+type EnvironmentContextValue = {
+ /** The string value representing the current environment */
+ environment: EnvironmentValue;
+
+ /** The string value representing the URL of the current environment */
+ environmentURL: string;
+};
+
+const EnvironmentContext = createContext(null);
+
+function EnvironmentProvider({children}: EnvironmentProviderProps): ReactElement {
+ const [environment, setEnvironment] = useState(CONST.ENVIRONMENT.PRODUCTION);
+ const [environmentURL, setEnvironmentURL] = useState(CONST.NEW_EXPENSIFY_URL);
+
+ useEffect(() => {
+ Environment.getEnvironment().then(setEnvironment);
+ Environment.getEnvironmentURL().then(setEnvironmentURL);
+ }, []);
+
+ const contextValue = useMemo(
+ (): EnvironmentContextValue => ({
+ environment,
+ environmentURL,
+ }),
+ [environment, environmentURL],
+ );
+
+ return {children} ;
+}
+
+EnvironmentProvider.displayName = 'EnvironmentProvider';
+
+export default function withEnvironment(
+ WrappedComponent: ComponentType>,
+): (props: Omit & React.RefAttributes) => ReactElement | null {
+ function WithEnvironment(props: Omit, ref: ForwardedRef): ReactElement {
+ const {environment, environmentURL} = useContext(EnvironmentContext) ?? {};
+ return (
+
+ );
+ }
+
+ WithEnvironment.displayName = `withEnvironment(${getComponentDisplayName(WrappedComponent)})`;
+
+ return forwardRef(WithEnvironment);
+}
+
+export {EnvironmentContext, EnvironmentProvider};
+export type {EnvironmentContextValue};
diff --git a/src/components/withKeyboardState.js b/src/components/withKeyboardState.js
index 3154f7e98d67..d89a4a8228bf 100755
--- a/src/components/withKeyboardState.js
+++ b/src/components/withKeyboardState.js
@@ -1,7 +1,7 @@
-import React, {forwardRef, createContext, useEffect, useState, useMemo} from 'react';
-import {Keyboard} from 'react-native';
import PropTypes from 'prop-types';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
+import React, {createContext, forwardRef, useEffect, useMemo, useState} from 'react';
+import {Keyboard} from 'react-native';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
const KeyboardStateContext = createContext(null);
const keyboardStatePropTypes = {
diff --git a/src/components/withLocalize.js b/src/components/withLocalize.js
index 65e98f78f312..346d402829bd 100755
--- a/src/components/withLocalize.js
+++ b/src/components/withLocalize.js
@@ -1,7 +1,7 @@
-import React, {forwardRef} from 'react';
import PropTypes from 'prop-types';
+import React, {forwardRef} from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
import {LocaleContext} from './LocaleContextProvider';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
const withLocalizePropTypes = {
/** Returns translated string for given locale and phrase */
diff --git a/src/components/withNavigation.tsx b/src/components/withNavigation.tsx
index c5842fdacc44..0834eabc2adb 100644
--- a/src/components/withNavigation.tsx
+++ b/src/components/withNavigation.tsx
@@ -1,6 +1,6 @@
-import React, {ComponentType, ForwardedRef, RefAttributes} from 'react';
import {NavigationProp, useNavigation} from '@react-navigation/native';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
+import React, {ComponentType, ForwardedRef, RefAttributes} from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
type WithNavigationProps = {
navigation: NavigationProp;
diff --git a/src/components/withNavigationFallback.js b/src/components/withNavigationFallback.js
index e82946c9e049..a03c1155fa46 100644
--- a/src/components/withNavigationFallback.js
+++ b/src/components/withNavigationFallback.js
@@ -1,6 +1,6 @@
-import React, {forwardRef, useContext, useMemo} from 'react';
import {NavigationContext} from '@react-navigation/core';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
+import React, {forwardRef, useContext, useMemo} from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
import refPropTypes from './refPropTypes';
export default function (WrappedComponent) {
@@ -33,11 +33,15 @@ export default function (WrappedComponent) {
forwardedRef: undefined,
};
- return forwardRef((props, ref) => (
+ const WithNavigationFallbackWithRef = forwardRef((props, ref) => (
));
+
+ WithNavigationFallbackWithRef.displayName = `WithNavigationFallbackWithRef`;
+
+ return WithNavigationFallbackWithRef;
}
diff --git a/src/components/withNavigationFocus.tsx b/src/components/withNavigationFocus.tsx
index f3f1d3561d9c..8dcd06ecb4c8 100644
--- a/src/components/withNavigationFocus.tsx
+++ b/src/components/withNavigationFocus.tsx
@@ -1,6 +1,6 @@
-import React, {ComponentType, ForwardedRef, RefAttributes} from 'react';
import {useIsFocused} from '@react-navigation/native';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
+import React, {ComponentType, ForwardedRef, RefAttributes} from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
type WithNavigationFocusProps = {
isFocused: boolean;
diff --git a/src/components/withTheme.js b/src/components/withTheme.js
index 99de2a2c7fc7..1d8af53de01d 100644
--- a/src/components/withTheme.js
+++ b/src/components/withTheme.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import useTheme from '../styles/themes/useTheme';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
+import React from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import useTheme from '@styles/themes/useTheme';
import refPropTypes from './refPropTypes';
const withThemePropTypes = {
@@ -28,13 +28,18 @@ export default function withTheme(WrappedComponent) {
WithTheme.defaultProps = {
forwardedRef: () => {},
};
- return React.forwardRef((props, ref) => (
+
+ const WithThemeWithRef = React.forwardRef((props, ref) => (
));
+
+ WithThemeWithRef.displayName = `WithThemeWithRef`;
+
+ return WithThemeWithRef;
}
export {withThemePropTypes};
diff --git a/src/components/withThemeStyles.js b/src/components/withThemeStyles.js
index 0320fcb71808..533efa79a580 100644
--- a/src/components/withThemeStyles.js
+++ b/src/components/withThemeStyles.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import useThemeStyles from '../styles/useThemeStyles';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
+import React from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import useThemeStyles from '@styles/useThemeStyles';
import refPropTypes from './refPropTypes';
const withThemeStylesPropTypes = {
@@ -28,13 +28,18 @@ export default function withThemeStyles(WrappedComponent) {
WithThemeStyles.defaultProps = {
forwardedRef: () => {},
};
- return React.forwardRef((props, ref) => (
+
+ const WithThemeStylesWithRef = React.forwardRef((props, ref) => (
));
+
+ WithThemeStylesWithRef.displayName = `WithThemeStylesWithRef`;
+
+ return WithThemeStylesWithRef;
}
export {withThemeStylesPropTypes};
diff --git a/src/components/withToggleVisibilityView.js b/src/components/withToggleVisibilityView.js
index eef5135d02b6..04c6ab8e8481 100644
--- a/src/components/withToggleVisibilityView.js
+++ b/src/components/withToggleVisibilityView.js
@@ -1,8 +1,8 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../styles/styles';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import styles from '@styles/styles';
import refPropTypes from './refPropTypes';
const toggleVisibilityViewPropTypes = {
@@ -35,13 +35,18 @@ export default function (WrappedComponent) {
forwardedRef: undefined,
isVisible: false,
};
- return React.forwardRef((props, ref) => (
+
+ const WithToggleVisibilityViewWithRef = React.forwardRef((props, ref) => (
));
+
+ WithToggleVisibilityViewWithRef.displayName = `WithToggleVisibilityViewWithRef`;
+
+ return WithToggleVisibilityViewWithRef;
}
export {toggleVisibilityViewPropTypes};
diff --git a/src/components/withViewportOffsetTop.tsx b/src/components/withViewportOffsetTop.tsx
index e2e1dc2d3484..d6c170b20480 100644
--- a/src/components/withViewportOffsetTop.tsx
+++ b/src/components/withViewportOffsetTop.tsx
@@ -1,6 +1,6 @@
-import React, {useEffect, forwardRef, useState, ComponentType, RefAttributes, ForwardedRef} from 'react';
-import getComponentDisplayName from '../libs/getComponentDisplayName';
-import addViewportResizeListener from '../libs/VisualViewport';
+import React, {ComponentType, ForwardedRef, forwardRef, RefAttributes, useEffect, useState} from 'react';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import addViewportResizeListener from '@libs/VisualViewport';
type ViewportOffsetTopProps = {
// viewportOffsetTop returns the offset of the top edge of the visual viewport from the
diff --git a/src/components/withWindowDimensions/index.js b/src/components/withWindowDimensions/index.js
index 16e5985e0985..f46624b2f41c 100644
--- a/src/components/withWindowDimensions/index.js
+++ b/src/components/withWindowDimensions/index.js
@@ -1,11 +1,11 @@
-import React, {forwardRef, createContext, useState, useEffect, useMemo} from 'react';
-import PropTypes from 'prop-types';
import lodashDebounce from 'lodash/debounce';
+import PropTypes from 'prop-types';
+import React, {createContext, forwardRef, useEffect, useMemo, useState} from 'react';
import {Dimensions} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
-import getComponentDisplayName from '../../libs/getComponentDisplayName';
-import variables from '../../styles/variables';
-import getWindowHeightAdjustment from '../../libs/getWindowHeightAdjustment';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment';
+import variables from '@styles/variables';
const WindowDimensionsContext = createContext(null);
const windowDimensionsPropTypes = {
diff --git a/src/components/withWindowDimensions/index.native.js b/src/components/withWindowDimensions/index.native.js
index 363196b3fd4d..91d81f5fb4e0 100644
--- a/src/components/withWindowDimensions/index.native.js
+++ b/src/components/withWindowDimensions/index.native.js
@@ -1,10 +1,10 @@
-import React, {forwardRef, createContext, useState, useEffect, useMemo} from 'react';
import PropTypes from 'prop-types';
+import React, {createContext, forwardRef, useEffect, useMemo, useState} from 'react';
import {Dimensions} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
-import getComponentDisplayName from '../../libs/getComponentDisplayName';
-import variables from '../../styles/variables';
-import getWindowHeightAdjustment from '../../libs/getWindowHeightAdjustment';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import getWindowHeightAdjustment from '@libs/getWindowHeightAdjustment';
+import variables from '@styles/variables';
const WindowDimensionsContext = createContext(null);
const windowDimensionsPropTypes = {
diff --git a/src/hooks/useArrowKeyFocusManager.js b/src/hooks/useArrowKeyFocusManager.js
index 58cecb169249..a633dba5ffc5 100644
--- a/src/hooks/useArrowKeyFocusManager.js
+++ b/src/hooks/useArrowKeyFocusManager.js
@@ -1,6 +1,6 @@
-import {useState, useEffect, useCallback, useMemo} from 'react';
+import {useCallback, useEffect, useMemo, useState} from 'react';
+import CONST from '@src/CONST';
import useKeyboardShortcut from './useKeyboardShortcut';
-import CONST from '../CONST';
/**
* A hook that makes it easy to use the arrow keys to manage focus of items in a list
diff --git a/src/hooks/useAutoFocusInput.js b/src/hooks/useAutoFocusInput.js
index 6611f867f210..275fed67f52d 100644
--- a/src/hooks/useAutoFocusInput.js
+++ b/src/hooks/useAutoFocusInput.js
@@ -1,6 +1,6 @@
import {useFocusEffect} from '@react-navigation/native';
-import {useState, useEffect, useRef, useCallback} from 'react';
-import CONST from '../CONST';
+import {useCallback, useEffect, useRef, useState} from 'react';
+import CONST from '@src/CONST';
export default function useAutoFocusInput() {
const [isInputInitialized, setIsInputInitialized] = useState(false);
diff --git a/src/hooks/useCopySelectionHelper.ts b/src/hooks/useCopySelectionHelper.ts
index b41bfb3c4aee..be7830dc6170 100644
--- a/src/hooks/useCopySelectionHelper.ts
+++ b/src/hooks/useCopySelectionHelper.ts
@@ -1,9 +1,9 @@
-import {useEffect} from 'react';
import ExpensiMark from 'expensify-common/lib/ExpensiMark';
-import CONST from '../CONST';
-import KeyboardShortcut from '../libs/KeyboardShortcut';
-import Clipboard from '../libs/Clipboard';
-import SelectionScraper from '../libs/SelectionScraper';
+import {useEffect} from 'react';
+import Clipboard from '@libs/Clipboard';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import SelectionScraper from '@libs/SelectionScraper';
+import CONST from '@src/CONST';
function copySelectionToClipboard() {
const selection = SelectionScraper.getCurrentSelection();
diff --git a/src/hooks/useCurrentReportID.js b/src/hooks/useCurrentReportID.js
index b22ac55616e8..1b3e4b706c4c 100644
--- a/src/hooks/useCurrentReportID.js
+++ b/src/hooks/useCurrentReportID.js
@@ -1,5 +1,5 @@
import {useContext} from 'react';
-import {CurrentReportIDContext} from '../components/withCurrentReportID';
+import {CurrentReportIDContext} from '@components/withCurrentReportID';
export default function useCurrentReportID() {
return useContext(CurrentReportIDContext);
diff --git a/src/hooks/useDebounce.js b/src/hooks/useDebounce.js
index 8995a0443b85..874f9d72b276 100644
--- a/src/hooks/useDebounce.js
+++ b/src/hooks/useDebounce.js
@@ -1,5 +1,5 @@
-import {useEffect, useRef} from 'react';
import lodashDebounce from 'lodash/debounce';
+import {useEffect, useRef} from 'react';
/**
* Create and return a debounced function.
diff --git a/src/hooks/useDelayedInputFocus.js b/src/hooks/useDelayedInputFocus.js
index 2fd94327a588..7a4a64104e48 100644
--- a/src/hooks/useDelayedInputFocus.js
+++ b/src/hooks/useDelayedInputFocus.js
@@ -1,6 +1,6 @@
-import {useCallback, useRef} from 'react';
import {useFocusEffect} from '@react-navigation/native';
-import CONST from '../CONST';
+import {useCallback, useRef} from 'react';
+import CONST from '@src/CONST';
/**
* Focus a text input when a screen is navigated to, after the specified time delay has elapsed.
diff --git a/src/hooks/useDragAndDrop.ts b/src/hooks/useDragAndDrop.ts
index 27230dd94679..3f0142492d0d 100644
--- a/src/hooks/useDragAndDrop.ts
+++ b/src/hooks/useDragAndDrop.ts
@@ -1,5 +1,5 @@
-import React, {useEffect, useRef, useState, useCallback} from 'react';
import {useIsFocused} from '@react-navigation/native';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
const COPY_DROP_EFFECT = 'copy';
const NONE_DROP_EFFECT = 'none';
diff --git a/src/hooks/useEnvironment.js b/src/hooks/useEnvironment.js
deleted file mode 100644
index e29e60a563b2..000000000000
--- a/src/hooks/useEnvironment.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import {useContext} from 'react';
-import CONST from '../CONST';
-import {EnvironmentContext} from '../components/withEnvironment';
-
-export default function useEnvironment() {
- const {environment, environmentURL} = useContext(EnvironmentContext);
- return {
- environment,
- environmentURL,
- isProduction: environment === CONST.ENVIRONMENT.PRODUCTION,
- isDevelopment: environment === CONST.ENVIRONMENT.DEV,
- };
-}
diff --git a/src/hooks/useEnvironment.ts b/src/hooks/useEnvironment.ts
new file mode 100644
index 000000000000..60e0b4a12394
--- /dev/null
+++ b/src/hooks/useEnvironment.ts
@@ -0,0 +1,19 @@
+import {useContext} from 'react';
+import {EnvironmentContext} from '@components/withEnvironment';
+import type {EnvironmentContextValue} from '@components/withEnvironment';
+import CONST from '@src/CONST';
+
+type UseEnvironment = Partial & {
+ isProduction: boolean;
+ isDevelopment: boolean;
+};
+
+export default function useEnvironment(): UseEnvironment {
+ const {environment, environmentURL} = useContext(EnvironmentContext) ?? {};
+ return {
+ environment,
+ environmentURL,
+ isProduction: environment === CONST.ENVIRONMENT.PRODUCTION,
+ isDevelopment: environment === CONST.ENVIRONMENT.DEV,
+ };
+}
diff --git a/src/hooks/useInitialValue.ts b/src/hooks/useInitialValue.ts
new file mode 100644
index 000000000000..e42ea044e27a
--- /dev/null
+++ b/src/hooks/useInitialValue.ts
@@ -0,0 +1,9 @@
+import {useState} from 'react';
+
+// In some places we set initial value on first render, but we don't want to re-run the function
+// This hook will memoize the initial value and return that without setter, so it's never changed
+// https://github.com/Expensify/App/pull/29643#issuecomment-1765894078
+export default function useInitialValue(initialStateFunc: () => T) {
+ const [initialValue] = useState(initialStateFunc);
+ return initialValue;
+}
diff --git a/src/hooks/useKeyboardShortcut.js b/src/hooks/useKeyboardShortcut.js
index b8e297c966ed..470d29243fe8 100644
--- a/src/hooks/useKeyboardShortcut.js
+++ b/src/hooks/useKeyboardShortcut.js
@@ -1,6 +1,6 @@
import {useEffect} from 'react';
-import KeyboardShortcut from '../libs/KeyboardShortcut';
-import CONST from '../CONST';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import CONST from '@src/CONST';
/**
* Register a keyboard shortcut handler.
diff --git a/src/hooks/useKeyboardState.js b/src/hooks/useKeyboardState.js
index 8b57fb60f2b6..68e9dbfc2b13 100644
--- a/src/hooks/useKeyboardState.js
+++ b/src/hooks/useKeyboardState.js
@@ -1,5 +1,5 @@
import {useContext} from 'react';
-import {KeyboardStateContext} from '../components/withKeyboardState';
+import {KeyboardStateContext} from '@components/withKeyboardState';
/**
* Hook for getting current state of keyboard
diff --git a/src/hooks/useLocalize.js b/src/hooks/useLocalize.js
index 7f7a610fca8b..71968cdb6e61 100644
--- a/src/hooks/useLocalize.js
+++ b/src/hooks/useLocalize.js
@@ -1,5 +1,5 @@
import {useContext} from 'react';
-import {LocaleContext} from '../components/LocaleContextProvider';
+import {LocaleContext} from '@components/LocaleContextProvider';
export default function useLocalize() {
return useContext(LocaleContext);
diff --git a/src/hooks/useNetwork.ts b/src/hooks/useNetwork.ts
index 4405dd7126a5..f9e1a627c5f5 100644
--- a/src/hooks/useNetwork.ts
+++ b/src/hooks/useNetwork.ts
@@ -1,5 +1,5 @@
-import {useRef, useContext, useEffect} from 'react';
-import {NetworkContext} from '../components/OnyxProvider';
+import {useContext, useEffect, useRef} from 'react';
+import {NetworkContext} from '@components/OnyxProvider';
type UseNetworkProps = {
onReconnect?: () => void;
diff --git a/src/hooks/usePermissions.ts b/src/hooks/usePermissions.ts
index 09e87554b5c3..e60825b610e9 100644
--- a/src/hooks/usePermissions.ts
+++ b/src/hooks/usePermissions.ts
@@ -1,6 +1,6 @@
import {useContext, useMemo} from 'react';
-import Permissions from '../libs/Permissions';
-import {BetasContext} from '../components/OnyxProvider';
+import {BetasContext} from '@components/OnyxProvider';
+import Permissions from '@libs/Permissions';
type PermissionKey = keyof typeof Permissions;
type UsePermissions = Partial>;
diff --git a/src/hooks/usePrivatePersonalDetails.js b/src/hooks/usePrivatePersonalDetails.js
index 14c1e42e629a..04d90f1ce5de 100644
--- a/src/hooks/usePrivatePersonalDetails.js
+++ b/src/hooks/usePrivatePersonalDetails.js
@@ -1,7 +1,7 @@
-import {useEffect, useContext} from 'react';
+import {useContext, useEffect} from 'react';
import _ from 'underscore';
-import * as PersonalDetails from '../libs/actions/PersonalDetails';
-import {NetworkContext} from '../components/OnyxProvider';
+import {NetworkContext} from '@components/OnyxProvider';
+import * as PersonalDetails from '@userActions/PersonalDetails';
/**
* Hook for fetching private personal details
diff --git a/src/hooks/useReportScrollManager/index.native.js b/src/hooks/useReportScrollManager/index.native.ts
similarity index 55%
rename from src/hooks/useReportScrollManager/index.native.js
rename to src/hooks/useReportScrollManager/index.native.ts
index d44a40222ca5..0d4c956b7bd8 100644
--- a/src/hooks/useReportScrollManager/index.native.js
+++ b/src/hooks/useReportScrollManager/index.native.ts
@@ -1,27 +1,26 @@
-import {useContext, useCallback} from 'react';
-import {ActionListContext} from '../../pages/home/ReportScreenContext';
+import {useCallback, useContext} from 'react';
+import {ActionListContext} from '@pages/home/ReportScreenContext';
+import ReportScrollManagerData from './types';
-function useReportScrollManager() {
+function useReportScrollManager(): ReportScrollManagerData {
const flatListRef = useContext(ActionListContext);
/**
* Scroll to the provided index.
- *
- * @param {Object} index
*/
- const scrollToIndex = (index) => {
- if (!flatListRef.current) {
+ const scrollToIndex = (index: number) => {
+ if (!flatListRef?.current) {
return;
}
- flatListRef.current.scrollToIndex(index);
+ flatListRef.current.scrollToIndex({index});
};
/**
* Scroll to the bottom of the flatlist.
*/
const scrollToBottom = useCallback(() => {
- if (!flatListRef.current) {
+ if (!flatListRef?.current) {
return;
}
diff --git a/src/hooks/useReportScrollManager/index.js b/src/hooks/useReportScrollManager/index.ts
similarity index 57%
rename from src/hooks/useReportScrollManager/index.js
rename to src/hooks/useReportScrollManager/index.ts
index 9a3303504b92..081844fc8c79 100644
--- a/src/hooks/useReportScrollManager/index.js
+++ b/src/hooks/useReportScrollManager/index.ts
@@ -1,29 +1,27 @@
-import {useContext, useCallback} from 'react';
-import {ActionListContext} from '../../pages/home/ReportScreenContext';
+import {useCallback, useContext} from 'react';
+import {ActionListContext} from '@pages/home/ReportScreenContext';
+import ReportScrollManagerData from './types';
-function useReportScrollManager() {
+function useReportScrollManager(): ReportScrollManagerData {
const flatListRef = useContext(ActionListContext);
/**
* Scroll to the provided index. On non-native implementations we do not want to scroll when we are scrolling because
* we are editing a comment.
- *
- * @param {Object} index
- * @param {Boolean} isEditing
*/
- const scrollToIndex = (index, isEditing) => {
- if (!flatListRef.current || isEditing) {
+ const scrollToIndex = (index: number, isEditing?: boolean) => {
+ if (!flatListRef?.current || isEditing) {
return;
}
- flatListRef.current.scrollToIndex(index);
+ flatListRef.current.scrollToIndex({index, animated: true});
};
/**
* Scroll to the bottom of the flatlist.
*/
const scrollToBottom = useCallback(() => {
- if (!flatListRef.current) {
+ if (!flatListRef?.current) {
return;
}
diff --git a/src/hooks/useReportScrollManager/types.ts b/src/hooks/useReportScrollManager/types.ts
new file mode 100644
index 000000000000..a10238d51f74
--- /dev/null
+++ b/src/hooks/useReportScrollManager/types.ts
@@ -0,0 +1,9 @@
+import {ActionListContextType} from '@pages/home/ReportScreenContext';
+
+type ReportScrollManagerData = {
+ ref: ActionListContextType;
+ scrollToIndex: (index: number, isEditing?: boolean) => void;
+ scrollToBottom: () => void;
+};
+
+export default ReportScrollManagerData;
diff --git a/src/hooks/useSingleExecution.js b/src/hooks/useSingleExecution.js
index 0b466252ed58..a2b4ccb4cd53 100644
--- a/src/hooks/useSingleExecution.js
+++ b/src/hooks/useSingleExecution.js
@@ -1,5 +1,5 @@
+import {useCallback, useRef, useState} from 'react';
import {InteractionManager} from 'react-native';
-import {useCallback, useState, useRef} from 'react';
/**
* With any action passed in, it will only allow 1 such action to occur at a time.
diff --git a/src/hooks/useWaitForNavigation.js b/src/hooks/useWaitForNavigation.js
index 00f4405dff12..81c26d7beb46 100644
--- a/src/hooks/useWaitForNavigation.js
+++ b/src/hooks/useWaitForNavigation.js
@@ -1,5 +1,5 @@
-import {useEffect, useRef} from 'react';
import {useNavigation} from '@react-navigation/native';
+import {useEffect, useRef} from 'react';
/**
* Returns a promise that resolves when navigation finishes.
diff --git a/src/hooks/useWindowDimensions/index.native.ts b/src/hooks/useWindowDimensions/index.native.ts
index 5b0ec2002201..e0268445fe4e 100644
--- a/src/hooks/useWindowDimensions/index.native.ts
+++ b/src/hooks/useWindowDimensions/index.native.ts
@@ -1,6 +1,6 @@
// eslint-disable-next-line no-restricted-imports
import {useWindowDimensions} from 'react-native';
-import variables from '../../styles/variables';
+import variables from '@styles/variables';
import WindowDimensions from './types';
/**
diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts
index f9fee6301d06..ab856bcf8e1b 100644
--- a/src/hooks/useWindowDimensions/index.ts
+++ b/src/hooks/useWindowDimensions/index.ts
@@ -1,6 +1,6 @@
// eslint-disable-next-line no-restricted-imports
import {Dimensions, useWindowDimensions} from 'react-native';
-import variables from '../../styles/variables';
+import variables from '@styles/variables';
import WindowDimensions from './types';
/**
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 1e8989e3e2a6..7cdce062faac 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -1,84 +1,84 @@
import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST';
-import CONST from '../CONST';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import CONST from '@src/CONST';
import type {
AddressLineParams,
- CharacterLimitParams,
- MaxParticipantsReachedParams,
- ZipCodeExampleFormatParams,
- LoggedInAsParams,
- NewFaceEnterMagicCodeParams,
- WelcomeEnterMagicCodeParams,
AlreadySignedInParams,
- GoBackMessageParams,
- LocalTimeParams,
- EditActionParams,
- DeleteActionParams,
- DeleteConfirmationParams,
- BeginningOfChatHistoryDomainRoomPartOneParams,
+ AmountEachParams,
BeginningOfChatHistoryAdminRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartTwo,
- WelcomeToRoomParams,
- ReportArchiveReasonsClosedParams,
- ReportArchiveReasonsMergedParams,
- ReportArchiveReasonsRemovedFromPolicyParams,
- ReportArchiveReasonsPolicyDeletedParams,
- RequestCountParams,
- SettleExpensifyCardParams,
- RequestAmountParams,
- SplitAmountParams,
+ BeginningOfChatHistoryDomainRoomPartOneParams,
+ CharacterLimitParams,
+ ConfirmThatParams,
+ DateShouldBeAfterParams,
+ DateShouldBeBeforeParams,
+ DeleteActionParams,
+ DeleteConfirmationParams,
DidSplitAmountMessageParams,
- AmountEachParams,
+ EditActionParams,
+ EnterMagicCodeParams,
+ FormattedMaxLengthParams,
+ GoBackMessageParams,
+ GoToRoomParams,
+ IncorrectZipFormatParams,
+ InstantSummaryParams,
+ LocalTimeParams,
+ LoggedInAsParams,
+ ManagerApprovedParams,
+ MaxParticipantsReachedParams,
+ NewFaceEnterMagicCodeParams,
+ NoLongerHaveAccessParams,
+ NotAllowedExtensionParams,
+ NotYouParams,
+ OOOEventSummaryFullDayParams,
+ OOOEventSummaryPartialDayParams,
+ OurEmailProviderParams,
+ PaidElsewhereWithAmountParams,
+ PaidWithExpensifyWithAmountParams,
+ ParentNavigationSummaryParams,
PayerOwesAmountParams,
PayerOwesParams,
PayerPaidAmountParams,
PayerPaidParams,
PayerSettledParams,
- WaitingOnBankAccountParams,
- SettledAfterAddedBankAccountParams,
- PaidElsewhereWithAmountParams,
- PaidWithExpensifyWithAmountParams,
- ThreadRequestReportNameParams,
- ThreadSentMoneyReportNameParams,
- SizeExceededParams,
+ RemovedTheRequestParams,
+ RenamedRoomActionParams,
+ ReportArchiveReasonsClosedParams,
+ ReportArchiveReasonsMergedParams,
+ ReportArchiveReasonsPolicyDeletedParams,
+ ReportArchiveReasonsRemovedFromPolicyParams,
+ RequestAmountParams,
+ RequestCountParams,
+ RequestedAmountMessageParams,
ResolutionConstraintsParams,
- NotAllowedExtensionParams,
- EnterMagicCodeParams,
- TransferParams,
- InstantSummaryParams,
- NotYouParams,
- DateShouldBeBeforeParams,
- DateShouldBeAfterParams,
- IncorrectZipFormatParams,
- WeSentYouMagicSignInLinkParams,
- ToValidateLoginParams,
- NoLongerHaveAccessParams,
- OurEmailProviderParams,
- ConfirmThatParams,
- UntilTimeParams,
- StepCounterParams,
- UserIsAlreadyMemberParams,
- GoToRoomParams,
- WelcomeNoteParams,
RoomNameReservedErrorParams,
- RenamedRoomActionParams,
RoomRenamedToParams,
- OOOEventSummaryFullDayParams,
- OOOEventSummaryPartialDayParams,
- ParentNavigationSummaryParams,
- ManagerApprovedParams,
- SetTheRequestParams,
- UpdatedTheRequestParams,
SetTheDistanceParams,
- UpdatedTheDistanceParams,
- RemovedTheRequestParams,
- FormattedMaxLengthParams,
- RequestedAmountMessageParams,
+ SetTheRequestParams,
+ SettledAfterAddedBankAccountParams,
+ SettleExpensifyCardParams,
+ SizeExceededParams,
+ SplitAmountParams,
+ StepCounterParams,
TagSelectionParams,
+ ThreadRequestReportNameParams,
+ ThreadSentMoneyReportNameParams,
+ ToValidateLoginParams,
+ TransferParams,
TranslationBase,
+ UntilTimeParams,
+ UpdatedTheDistanceParams,
+ UpdatedTheRequestParams,
+ UserIsAlreadyMemberParams,
+ WaitingOnBankAccountParams,
WalletProgramParams,
+ WelcomeEnterMagicCodeParams,
+ WelcomeNoteParams,
+ WelcomeToRoomParams,
+ WeSentYouMagicSignInLinkParams,
+ ZipCodeExampleFormatParams,
} from './types';
-import * as ReportActionsUtils from '../libs/ReportActionsUtils';
type StateValue = {
stateISO: string;
@@ -264,6 +264,7 @@ export default {
recent: 'Recent',
all: 'All',
tbd: 'TBD',
+ selectCurrency: 'Select a currency',
card: 'Card',
},
location: {
@@ -338,10 +339,6 @@ export default {
splitWith: 'Split with',
whatsItFor: "What's it for?",
},
- iOUCurrencySelection: {
- selectCurrency: 'Select a currency',
- allCurrencies: 'All currencies',
- },
optionsSelector: {
nameEmailOrPhoneNumber: 'Name, email, or phone number',
findMember: 'Find a member',
@@ -426,6 +423,8 @@ export default {
deleteConfirmation: ({action}: DeleteConfirmationParams) => `Are you sure you want to delete this ${ReportActionsUtils.isMoneyRequestAction(action) ? 'request' : 'comment'}?`,
onlyVisible: 'Only visible to',
replyInThread: 'Reply in thread',
+ subscribeToThread: 'Subscribe to thread',
+ unsubscribeFromThread: 'Unsubscribe from thread',
flagAsOffensive: 'Flag as offensive',
},
emojiReactions: {
@@ -1444,6 +1443,8 @@ export default {
cannotRemove: 'You cannot remove yourself or the workspace owner.',
genericRemove: 'There was a problem removing that workspace member.',
},
+ addedWithPrimary: 'Some users were added with their primary logins.',
+ invitedBySecondaryLogin: ({secondaryLogin}) => `Added by secondary login ${secondaryLogin}.`,
},
card: {
header: 'Unlock free Expensify Cards',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index 5f916711d221..578e027e1d14 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -1,82 +1,82 @@
-import CONST from '../CONST';
-import * as ReportActionsUtils from '../libs/ReportActionsUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import CONST from '@src/CONST';
import type {
AddressLineParams,
- CharacterLimitParams,
- MaxParticipantsReachedParams,
- ZipCodeExampleFormatParams,
- LoggedInAsParams,
- NewFaceEnterMagicCodeParams,
- WelcomeEnterMagicCodeParams,
AlreadySignedInParams,
- GoBackMessageParams,
- LocalTimeParams,
- EditActionParams,
- DeleteActionParams,
- DeleteConfirmationParams,
- BeginningOfChatHistoryDomainRoomPartOneParams,
+ AmountEachParams,
BeginningOfChatHistoryAdminRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartOneParams,
BeginningOfChatHistoryAnnounceRoomPartTwo,
- WelcomeToRoomParams,
- ReportArchiveReasonsClosedParams,
- ReportArchiveReasonsMergedParams,
- ReportArchiveReasonsRemovedFromPolicyParams,
- ReportArchiveReasonsPolicyDeletedParams,
- RequestCountParams,
- SettleExpensifyCardParams,
- RequestAmountParams,
- SplitAmountParams,
+ BeginningOfChatHistoryDomainRoomPartOneParams,
+ CharacterLimitParams,
+ ConfirmThatParams,
+ DateShouldBeAfterParams,
+ DateShouldBeBeforeParams,
+ DeleteActionParams,
+ DeleteConfirmationParams,
DidSplitAmountMessageParams,
- AmountEachParams,
+ EditActionParams,
+ EnglishTranslation,
+ EnterMagicCodeParams,
+ FormattedMaxLengthParams,
+ GoBackMessageParams,
+ GoToRoomParams,
+ IncorrectZipFormatParams,
+ InstantSummaryParams,
+ LocalTimeParams,
+ LoggedInAsParams,
+ ManagerApprovedParams,
+ MaxParticipantsReachedParams,
+ NewFaceEnterMagicCodeParams,
+ NoLongerHaveAccessParams,
+ NotAllowedExtensionParams,
+ NotYouParams,
+ OOOEventSummaryFullDayParams,
+ OOOEventSummaryPartialDayParams,
+ OurEmailProviderParams,
+ PaidElsewhereWithAmountParams,
+ PaidWithExpensifyWithAmountParams,
+ ParentNavigationSummaryParams,
PayerOwesAmountParams,
PayerOwesParams,
PayerPaidAmountParams,
PayerPaidParams,
PayerSettledParams,
- WaitingOnBankAccountParams,
+ RemovedTheRequestParams,
+ RenamedRoomActionParams,
+ ReportArchiveReasonsClosedParams,
+ ReportArchiveReasonsMergedParams,
+ ReportArchiveReasonsPolicyDeletedParams,
+ ReportArchiveReasonsRemovedFromPolicyParams,
+ RequestAmountParams,
+ RequestCountParams,
+ RequestedAmountMessageParams,
+ ResolutionConstraintsParams,
+ RoomNameReservedErrorParams,
+ RoomRenamedToParams,
+ SetTheDistanceParams,
+ SetTheRequestParams,
SettledAfterAddedBankAccountParams,
- PaidElsewhereWithAmountParams,
- PaidWithExpensifyWithAmountParams,
+ SettleExpensifyCardParams,
+ SizeExceededParams,
+ SplitAmountParams,
+ StepCounterParams,
+ TagSelectionParams,
ThreadRequestReportNameParams,
ThreadSentMoneyReportNameParams,
- SizeExceededParams,
- ResolutionConstraintsParams,
- NotAllowedExtensionParams,
- EnterMagicCodeParams,
- TransferParams,
- InstantSummaryParams,
- NotYouParams,
- DateShouldBeBeforeParams,
- DateShouldBeAfterParams,
- IncorrectZipFormatParams,
- WeSentYouMagicSignInLinkParams,
ToValidateLoginParams,
- NoLongerHaveAccessParams,
- OurEmailProviderParams,
- ConfirmThatParams,
+ TransferParams,
UntilTimeParams,
- StepCounterParams,
- UserIsAlreadyMemberParams,
- GoToRoomParams,
- WelcomeNoteParams,
- RoomNameReservedErrorParams,
- RenamedRoomActionParams,
- RoomRenamedToParams,
- OOOEventSummaryFullDayParams,
- OOOEventSummaryPartialDayParams,
- ParentNavigationSummaryParams,
- ManagerApprovedParams,
- SetTheRequestParams,
- SetTheDistanceParams,
- UpdatedTheRequestParams,
UpdatedTheDistanceParams,
- RemovedTheRequestParams,
- FormattedMaxLengthParams,
- RequestedAmountMessageParams,
- TagSelectionParams,
- EnglishTranslation,
+ UpdatedTheRequestParams,
+ UserIsAlreadyMemberParams,
+ WaitingOnBankAccountParams,
WalletProgramParams,
+ WelcomeEnterMagicCodeParams,
+ WelcomeNoteParams,
+ WelcomeToRoomParams,
+ WeSentYouMagicSignInLinkParams,
+ ZipCodeExampleFormatParams,
} from './types';
/* eslint-disable max-len */
@@ -254,6 +254,7 @@ export default {
recent: 'Reciente',
all: 'Todo',
tbd: 'Por determinar',
+ selectCurrency: 'Selecciona una moneda',
card: 'Tarjeta',
},
location: {
@@ -329,10 +330,6 @@ export default {
splitWith: 'Dividir con',
whatsItFor: '¿Para qué es?',
},
- iOUCurrencySelection: {
- selectCurrency: 'Selecciona una moneda',
- allCurrencies: 'Todas las monedas',
- },
optionsSelector: {
nameEmailOrPhoneNumber: 'Nombre, email o número de teléfono',
findMember: 'Encuentra un miembro',
@@ -417,6 +414,8 @@ export default {
deleteConfirmation: ({action}: DeleteConfirmationParams) => `¿Estás seguro de que quieres eliminar este ${ReportActionsUtils.isMoneyRequestAction(action) ? 'pedido' : 'comentario'}`,
onlyVisible: 'Visible sólo para',
replyInThread: 'Responder en el hilo',
+ subscribeToThread: 'Suscribirse al hilo',
+ unsubscribeFromThread: 'Darse de baja del hilo',
flagAsOffensive: 'Marcar como ofensivo',
},
emojiReactions: {
@@ -590,7 +589,7 @@ export default {
duplicateWaypointsErrorMessage: 'Por favor elimina los puntos de ruta duplicados',
emptyWaypointsErrorMessage: 'Por favor introduce al menos dos puntos de ruta',
},
- waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `nicio el pago, pero no se procesará hasta que ${submitterDisplayName} active su Billetera`,
+ waitingOnEnabledWallet: ({submitterDisplayName}: WaitingOnBankAccountParams) => `Inició el pago, pero no se procesará hasta que ${submitterDisplayName} active su Billetera`,
enableWallet: 'Habilitar Billetera',
},
notificationPreferencesPage: {
@@ -1465,6 +1464,8 @@ export default {
cannotRemove: 'No puedes eliminarte ni a ti mismo ni al dueño del espacio de trabajo.',
genericRemove: 'Ha ocurrido un problema al eliminar al miembro del espacio de trabajo.',
},
+ addedWithPrimary: 'Se agregaron algunos usuarios con sus nombres de usuario principales.',
+ invitedBySecondaryLogin: ({secondaryLogin}) => `Agregado por nombre de usuario secundario ${secondaryLogin}.`,
},
card: {
header: 'Desbloquea Tarjetas Expensify gratis',
diff --git a/src/languages/types.ts b/src/languages/types.ts
index 5a1847e31e71..d2a387a329d0 100644
--- a/src/languages/types.ts
+++ b/src/languages/types.ts
@@ -1,4 +1,4 @@
-import {ReportAction} from '../types/onyx';
+import {ReportAction} from '@src/types/onyx';
import en from './en';
type AddressLineParams = {
diff --git a/src/libs/API.ts b/src/libs/API.ts
index ce3d6bab19bc..91cf6a7db877 100644
--- a/src/libs/API.ts
+++ b/src/libs/API.ts
@@ -1,14 +1,14 @@
import Onyx, {OnyxUpdate} from 'react-native-onyx';
import {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
+import OnyxRequest from '@src/types/onyx/Request';
+import Response from '@src/types/onyx/Response';
+import pkg from '../../package.json';
import Log from './Log';
-import * as Request from './Request';
import * as Middleware from './Middleware';
import * as SequentialQueue from './Network/SequentialQueue';
-import pkg from '../../package.json';
-import CONST from '../CONST';
import * as Pusher from './Pusher/pusher';
-import OnyxRequest from '../types/onyx/Request';
-import Response from '../types/onyx/Response';
+import * as Request from './Request';
// Setup API middlewares. Each request made will pass through a series of middleware functions that will get called in sequence (each one passing the result of the previous to the next).
// Note: The ordering here is intentional as we want to Log, Recheck Connection, Reauthenticate, and Save the Response in Onyx. Errors thrown in one middleware will bubble to the next.
diff --git a/src/libs/Accessibility/index.ts b/src/libs/Accessibility/index.ts
index 213d28139c2c..5eceda8edcb1 100644
--- a/src/libs/Accessibility/index.ts
+++ b/src/libs/Accessibility/index.ts
@@ -1,4 +1,4 @@
-import {useEffect, useState, useCallback} from 'react';
+import {useCallback, useEffect, useState} from 'react';
import {AccessibilityInfo, LayoutChangeEvent} from 'react-native';
import moveAccessibilityFocus from './moveAccessibilityFocus';
diff --git a/src/libs/ActiveClientManager/index.native.ts b/src/libs/ActiveClientManager/index.native.ts
index 1d455a84a28a..866992bcc841 100644
--- a/src/libs/ActiveClientManager/index.native.ts
+++ b/src/libs/ActiveClientManager/index.native.ts
@@ -2,8 +2,7 @@
* For native devices, there will never be more than one
* client running at a time, so this lib is a big no-op
*/
-
-import {Init, IsReady, IsClientTheLeader} from './types';
+import {Init, IsClientTheLeader, IsReady} from './types';
const init: Init = () => {};
diff --git a/src/libs/ActiveClientManager/index.ts b/src/libs/ActiveClientManager/index.ts
index f99f54e84aa5..0baeb2becfce 100644
--- a/src/libs/ActiveClientManager/index.ts
+++ b/src/libs/ActiveClientManager/index.ts
@@ -3,12 +3,11 @@
* only one tab is processing those saved requests or we would be duplicating data (or creating errors).
* This file ensures exactly that by tracking all the clientIDs connected, storing the most recent one last and it considers that last clientID the "leader".
*/
-
-import Onyx from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as ActiveClients from '../actions/ActiveClients';
-import {Init, IsReady, IsClientTheLeader} from './types';
+import Onyx from 'react-native-onyx';
+import * as ActiveClients from '@userActions/ActiveClients';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {Init, IsClientTheLeader, IsReady} from './types';
const clientID = Str.guid();
const maxClients = 20;
diff --git a/src/libs/ApiUtils.ts b/src/libs/ApiUtils.ts
index 87a251ccb086..a15c900b9387 100644
--- a/src/libs/ApiUtils.ts
+++ b/src/libs/ApiUtils.ts
@@ -1,10 +1,10 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
-import CONFIG from '../CONFIG';
-import CONST from '../CONST';
-import * as Environment from './Environment/Environment';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {Request} from '@src/types/onyx';
import proxyConfig from '../../config/proxyConfig';
-import {Request} from '../types/onyx';
+import * as Environment from './Environment/Environment';
// 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
diff --git a/src/libs/AppStateMonitor/index.ts b/src/libs/AppStateMonitor/index.ts
index 5c206579944d..f95fad042b98 100644
--- a/src/libs/AppStateMonitor/index.ts
+++ b/src/libs/AppStateMonitor/index.ts
@@ -1,5 +1,5 @@
import {AppState, AppStateStatus} from 'react-native';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import shouldReportActivity from './shouldReportActivity';
let appState: AppStateStatus = CONST.APP_STATE.ACTIVE;
diff --git a/src/libs/Authentication.ts b/src/libs/Authentication.ts
index cec20504dd04..9962fa55b0af 100644
--- a/src/libs/Authentication.ts
+++ b/src/libs/Authentication.ts
@@ -1,13 +1,13 @@
-import requireParameters from './requireParameters';
-import * as Network from './Network';
-import * as NetworkStore from './Network/NetworkStore';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import Response from '@src/types/onyx/Response';
import updateSessionAuthTokens from './actions/Session/updateSessionAuthTokens';
-import CONFIG from '../CONFIG';
import redirectToSignIn from './actions/SignInRedirect';
-import CONST from '../CONST';
-import Log from './Log';
import * as ErrorUtils from './ErrorUtils';
-import Response from '../types/onyx/Response';
+import Log from './Log';
+import * as Network from './Network';
+import * as NetworkStore from './Network/NetworkStore';
+import requireParameters from './requireParameters';
type Parameters = {
useExpensifyLogin?: boolean;
diff --git a/src/libs/BootSplash/index.native.ts b/src/libs/BootSplash/index.native.ts
index 307d0d62c8dd..9d472aec4a96 100644
--- a/src/libs/BootSplash/index.native.ts
+++ b/src/libs/BootSplash/index.native.ts
@@ -1,5 +1,5 @@
import {NativeModules} from 'react-native';
-import Log from '../Log';
+import Log from '@libs/Log';
const BootSplash = NativeModules.BootSplash;
diff --git a/src/libs/BootSplash/index.ts b/src/libs/BootSplash/index.ts
index e58763039129..605e65a21a7b 100644
--- a/src/libs/BootSplash/index.ts
+++ b/src/libs/BootSplash/index.ts
@@ -1,4 +1,4 @@
-import Log from '../Log';
+import Log from '@libs/Log';
import {VisibilityStatus} from './types';
function resolveAfter(delay: number): Promise {
diff --git a/src/libs/Browser/index.web.ts b/src/libs/Browser/index.web.ts
index 064358c6bed5..2ce4c5ad2040 100644
--- a/src/libs/Browser/index.web.ts
+++ b/src/libs/Browser/index.web.ts
@@ -1,6 +1,6 @@
-import CONST from '../../CONST';
-import CONFIG from '../../CONFIG';
-import ROUTES from '../../ROUTES';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
/**
* Fetch browser name from UA string
diff --git a/src/libs/CardUtils.ts b/src/libs/CardUtils.ts
index 52c4f7067acf..0dc483aff50e 100644
--- a/src/libs/CardUtils.ts
+++ b/src/libs/CardUtils.ts
@@ -1,10 +1,10 @@
import lodash from 'lodash';
import Onyx from 'react-native-onyx';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
+import ONYXKEYS, {OnyxValues} from '@src/ONYXKEYS';
+import * as OnyxTypes from '@src/types/onyx';
+import {Card} from '@src/types/onyx';
import * as Localize from './Localize';
-import * as OnyxTypes from '../types/onyx';
-import ONYXKEYS, {OnyxValues} from '../ONYXKEYS';
-import {Card} from '../types/onyx';
let allCards: OnyxValues[typeof ONYXKEYS.CARD_LIST] = {};
Onyx.connect({
diff --git a/src/libs/Clipboard/index.js b/src/libs/Clipboard/index.js
index 6fbaa8eccd31..ff05fcb45d0a 100644
--- a/src/libs/Clipboard/index.js
+++ b/src/libs/Clipboard/index.js
@@ -1,7 +1,7 @@
import Clipboard from '@react-native-clipboard/clipboard';
import lodashGet from 'lodash/get';
-import CONST from '../../CONST';
-import * as Browser from '../Browser';
+import * as Browser from '@libs/Browser';
+import CONST from '@src/CONST';
const canSetHtml = () => lodashGet(navigator, 'clipboard.write');
diff --git a/src/libs/CollectionUtils.ts b/src/libs/CollectionUtils.ts
index ac47633c2e08..3a980906d614 100644
--- a/src/libs/CollectionUtils.ts
+++ b/src/libs/CollectionUtils.ts
@@ -1,4 +1,4 @@
-import {OnyxCollectionKey} from '../ONYXKEYS';
+import {OnyxCollectionKey} from '@src/ONYXKEYS';
/**
* Return the highest item in a numbered collection
diff --git a/src/libs/ComposerUtils/getDraftComment.ts b/src/libs/ComposerUtils/getDraftComment.ts
index ac3d2f3d09be..97567a42b263 100644
--- a/src/libs/ComposerUtils/getDraftComment.ts
+++ b/src/libs/ComposerUtils/getDraftComment.ts
@@ -1,5 +1,5 @@
import Onyx, {OnyxEntry} from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
const draftCommentMap: Record> = {};
Onyx.connect({
diff --git a/src/libs/ComposerUtils/index.ts b/src/libs/ComposerUtils/index.ts
index 5e2a42fc65dd..5a7da7ca08cf 100644
--- a/src/libs/ComposerUtils/index.ts
+++ b/src/libs/ComposerUtils/index.ts
@@ -1,6 +1,6 @@
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import getNumberOfLines from './getNumberOfLines';
import updateNumberOfLines from './updateNumberOfLines';
-import * as DeviceCapabilities from '../DeviceCapabilities';
type Selection = {
start: number;
diff --git a/src/libs/ComposerUtils/updateIsFullComposerAvailable.ts b/src/libs/ComposerUtils/updateIsFullComposerAvailable.ts
index 5d73619482db..761abb8c9c8f 100644
--- a/src/libs/ComposerUtils/updateIsFullComposerAvailable.ts
+++ b/src/libs/ComposerUtils/updateIsFullComposerAvailable.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import ComposerProps from './types';
/**
diff --git a/src/libs/ComposerUtils/updateNumberOfLines/index.native.ts b/src/libs/ComposerUtils/updateNumberOfLines/index.native.ts
index b5c28cfc79e8..df9292ecd690 100644
--- a/src/libs/ComposerUtils/updateNumberOfLines/index.native.ts
+++ b/src/libs/ComposerUtils/updateNumberOfLines/index.native.ts
@@ -1,6 +1,6 @@
-import styles from '../../../styles/styles';
-import updateIsFullComposerAvailable from '../updateIsFullComposerAvailable';
-import getNumberOfLines from '../getNumberOfLines';
+import getNumberOfLines from '@libs/ComposerUtils/getNumberOfLines';
+import updateIsFullComposerAvailable from '@libs/ComposerUtils/updateIsFullComposerAvailable';
+import styles from '@styles/styles';
import UpdateNumberOfLines from './types';
/**
diff --git a/src/libs/ComposerUtils/updateNumberOfLines/types.ts b/src/libs/ComposerUtils/updateNumberOfLines/types.ts
index c0650be25433..b0f9ba48ddc2 100644
--- a/src/libs/ComposerUtils/updateNumberOfLines/types.ts
+++ b/src/libs/ComposerUtils/updateNumberOfLines/types.ts
@@ -1,5 +1,5 @@
import {NativeSyntheticEvent, TextInputContentSizeChangeEventData} from 'react-native';
-import ComposerProps from '../types';
+import ComposerProps from '@libs/ComposerUtils/types';
type UpdateNumberOfLines = (props: ComposerProps, event: NativeSyntheticEvent) => void;
diff --git a/src/libs/ControlSelection/index.ts b/src/libs/ControlSelection/index.ts
index 9625b4e49787..44d4530bc4fd 100644
--- a/src/libs/ControlSelection/index.ts
+++ b/src/libs/ControlSelection/index.ts
@@ -1,5 +1,5 @@
+import CustomRefObject from '@src/types/utils/CustomRefObject';
import ControlSelectionModule from './types';
-import CustomRefObject from '../../types/utils/CustomRefObject';
/**
* Block selection on the whole app
diff --git a/src/libs/ControlSelection/types.ts b/src/libs/ControlSelection/types.ts
index 5706a4981d30..d84347fd7ba6 100644
--- a/src/libs/ControlSelection/types.ts
+++ b/src/libs/ControlSelection/types.ts
@@ -1,4 +1,4 @@
-import CustomRefObject from '../../types/utils/CustomRefObject';
+import CustomRefObject from '@src/types/utils/CustomRefObject';
type ControlSelectionModule = {
block: () => void;
diff --git a/src/libs/CurrencyUtils.ts b/src/libs/CurrencyUtils.ts
index 85ba8340c13e..4829ce115592 100644
--- a/src/libs/CurrencyUtils.ts
+++ b/src/libs/CurrencyUtils.ts
@@ -1,8 +1,8 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS, {OnyxValues} from '../ONYXKEYS';
-import CONST from '../CONST';
-import BaseLocaleListener from './Localize/LocaleListener/BaseLocaleListener';
+import CONST from '@src/CONST';
+import ONYXKEYS, {OnyxValues} from '@src/ONYXKEYS';
import * as Localize from './Localize';
+import BaseLocaleListener from './Localize/LocaleListener/BaseLocaleListener';
import * as NumberFormatUtils from './NumberFormatUtils';
let currencyList: OnyxValues[typeof ONYXKEYS.CURRENCY_LIST] = {};
diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts
index a6f2860310c2..e03e3dd55680 100644
--- a/src/libs/DateUtils.ts
+++ b/src/libs/DateUtils.ts
@@ -1,29 +1,28 @@
-import {zonedTimeToUtc, utcToZonedTime, formatInTimeZone} from 'date-fns-tz';
-import {es, enGB} from 'date-fns/locale';
import {
- formatDistanceToNow,
- subMinutes,
addDays,
- subDays,
- isBefore,
- subMilliseconds,
- startOfWeek,
+ endOfDay,
endOfWeek,
format,
- setDefaultOptions,
- endOfDay,
- isSameDay,
+ formatDistanceToNow,
isAfter,
+ isBefore,
+ isSameDay,
isSameYear,
+ setDefaultOptions,
+ startOfWeek,
+ subDays,
+ subMilliseconds,
+ subMinutes,
} from 'date-fns';
-
-import Onyx from 'react-native-onyx';
+import {formatInTimeZone, utcToZonedTime, zonedTimeToUtc} from 'date-fns-tz';
+import {enGB, es} from 'date-fns/locale';
import throttle from 'lodash/throttle';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
-import * as Localize from './Localize';
+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 {Timezone} from '../types/onyx/PersonalDetails';
+import * as Localize from './Localize';
let currentUserAccountID: number | undefined;
Onyx.connect({
diff --git a/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/index.native.ts b/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/index.native.ts
new file mode 100644
index 000000000000..a5e57675fcf5
--- /dev/null
+++ b/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/index.native.ts
@@ -0,0 +1,8 @@
+import HasPassiveEventListenerSupport from './types';
+
+/**
+ * Allows us to identify whether the browser supports passive event listener.
+ */
+const hasPassiveEventListenerSupport: HasPassiveEventListenerSupport = () => false;
+
+export default hasPassiveEventListenerSupport;
diff --git a/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/index.ts b/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/index.ts
new file mode 100644
index 000000000000..d3c6af0766af
--- /dev/null
+++ b/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/index.ts
@@ -0,0 +1,18 @@
+/**
+ * Allows us to identify whether the browser supports passive event listener.
+ */
+export default function hasPassiveEventListenerSupport(): boolean {
+ let supportsPassive = false;
+ try {
+ const opts = Object.defineProperty({}, 'passive', {
+ // eslint-disable-next-line getter-return
+ get() {
+ supportsPassive = true;
+ },
+ });
+ window.addEventListener('testPassive', () => {}, opts);
+ window.removeEventListener('testPassive', () => {}, opts);
+ // eslint-disable-next-line no-empty
+ } catch (e) {}
+ return supportsPassive;
+}
diff --git a/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/types.ts b/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/types.ts
new file mode 100644
index 000000000000..2987bba0b28c
--- /dev/null
+++ b/src/libs/DeviceCapabilities/hasPassiveEventListenerSupport/types.ts
@@ -0,0 +1,3 @@
+type HasPassiveEventListenerSupport = () => boolean;
+
+export default HasPassiveEventListenerSupport;
diff --git a/src/libs/DeviceCapabilities/index.ts b/src/libs/DeviceCapabilities/index.ts
index 3759e4ade730..51c65fef3d5b 100644
--- a/src/libs/DeviceCapabilities/index.ts
+++ b/src/libs/DeviceCapabilities/index.ts
@@ -1,4 +1,5 @@
import canUseTouchScreen from './canUseTouchScreen';
import hasHoverSupport from './hasHoverSupport';
+import hasPassiveEventListenerSupport from './hasPassiveEventListenerSupport';
-export {canUseTouchScreen, hasHoverSupport};
+export {canUseTouchScreen, hasHoverSupport, hasPassiveEventListenerSupport};
diff --git a/src/libs/DistanceRequestUtils.js b/src/libs/DistanceRequestUtils.js
index 32de571c218c..0cc4e39d83af 100644
--- a/src/libs/DistanceRequestUtils.js
+++ b/src/libs/DistanceRequestUtils.js
@@ -1,5 +1,5 @@
import _ from 'underscore';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
import * as CurrencyUtils from './CurrencyUtils';
import * as PolicyUtils from './PolicyUtils';
diff --git a/src/libs/E2E/API.mock.js b/src/libs/E2E/API.mock.js
index 47f445f72222..2c7da3f420a3 100644
--- a/src/libs/E2E/API.mock.js
+++ b/src/libs/E2E/API.mock.js
@@ -1,14 +1,13 @@
/* eslint-disable rulesdir/no-api-in-views */
-import _ from 'underscore';
import Onyx from 'react-native-onyx';
-import Log from '../Log';
-
+import _ from 'underscore';
+import Log from '@libs/Log';
+import mockAuthenticatePusher from './apiMocks/authenticatePusher';
// mock functions
import mockBeginSignin from './apiMocks/beginSignin';
-import mockSigninUser from './apiMocks/signinUser';
-import mockAuthenticatePusher from './apiMocks/authenticatePusher';
import mockOpenApp from './apiMocks/openApp';
import mockOpenReport from './apiMocks/openReport';
+import mockSigninUser from './apiMocks/signinUser';
/**
* A dictionary which has the name of a API command as key, and a function which
diff --git a/src/libs/E2E/actions/e2eLogin.js b/src/libs/E2E/actions/e2eLogin.js
index 77576b09d88d..e2202f7e5662 100644
--- a/src/libs/E2E/actions/e2eLogin.js
+++ b/src/libs/E2E/actions/e2eLogin.js
@@ -1,7 +1,7 @@
/* eslint-disable rulesdir/prefer-onyx-connect-in-libs */
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as Session from '../../actions/Session';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Command for e2e test to automatically sign in a user.
diff --git a/src/libs/E2E/client.js b/src/libs/E2E/client.js
index c948c7c2c6d2..7e6932d9fce5 100644
--- a/src/libs/E2E/client.js
+++ b/src/libs/E2E/client.js
@@ -1,5 +1,5 @@
-import Routes from '../../../tests/e2e/server/routes';
import Config from '../../../tests/e2e/config';
+import Routes from '../../../tests/e2e/server/routes';
const SERVER_ADDRESS = `http://localhost:${Config.SERVER_PORT}`;
diff --git a/src/libs/E2E/isE2ETestSession.native.js b/src/libs/E2E/isE2ETestSession.native.js
index 214e8241c5dc..3c4c19e8ba24 100644
--- a/src/libs/E2E/isE2ETestSession.native.js
+++ b/src/libs/E2E/isE2ETestSession.native.js
@@ -1,3 +1,3 @@
-import CONFIG from '../../CONFIG';
+import CONFIG from '@src/CONFIG';
export default () => CONFIG.E2E_TESTING;
diff --git a/src/libs/E2E/reactNativeLaunchingTest.js b/src/libs/E2E/reactNativeLaunchingTest.js
index 13183c1044db..7621e462f8c5 100644
--- a/src/libs/E2E/reactNativeLaunchingTest.js
+++ b/src/libs/E2E/reactNativeLaunchingTest.js
@@ -1,13 +1,12 @@
/* eslint-disable import/newline-after-import,import/first */
+
/**
* We are using a separate entry point for the E2E tests.
* By doing this, we avoid bundling any E2E testing code
* into the actual release app.
*/
-
-import Performance from '../Performance';
-import * as Metrics from '../Metrics';
-
+import * as Metrics from '@libs/Metrics';
+import Performance from '@libs/Performance';
import E2EConfig from '../../../tests/e2e/config';
import E2EClient from './client';
diff --git a/src/libs/E2E/tests/appStartTimeTest.e2e.js b/src/libs/E2E/tests/appStartTimeTest.e2e.js
index d44fd6ce1195..311b891fcd4c 100644
--- a/src/libs/E2E/tests/appStartTimeTest.e2e.js
+++ b/src/libs/E2E/tests/appStartTimeTest.e2e.js
@@ -1,7 +1,7 @@
import _ from 'underscore';
-import E2ELogin from '../actions/e2eLogin';
-import Performance from '../../Performance';
-import E2EClient from '../client';
+import E2ELogin from '@libs/E2E/actions/e2eLogin';
+import E2EClient from '@libs/E2E/client';
+import Performance from '@libs/Performance';
const test = () => {
// check for login (if already logged in the action will simply resolve)
diff --git a/src/libs/E2E/tests/openSearchPageTest.e2e.js b/src/libs/E2E/tests/openSearchPageTest.e2e.js
index 3b2d91322cf0..1101a620f413 100644
--- a/src/libs/E2E/tests/openSearchPageTest.e2e.js
+++ b/src/libs/E2E/tests/openSearchPageTest.e2e.js
@@ -1,9 +1,9 @@
-import E2ELogin from '../actions/e2eLogin';
-import Performance from '../../Performance';
-import E2EClient from '../client';
-import Navigation from '../../Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import CONST from '../../../CONST';
+import E2ELogin from '@libs/E2E/actions/e2eLogin';
+import E2EClient from '@libs/E2E/client';
+import Navigation from '@libs/Navigation/Navigation';
+import Performance from '@libs/Performance';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const test = () => {
// check for login (if already logged in the action will simply resolve)
diff --git a/src/libs/EmojiTrie.ts b/src/libs/EmojiTrie.ts
index d0a53acf29c9..2ab950621f87 100644
--- a/src/libs/EmojiTrie.ts
+++ b/src/libs/EmojiTrie.ts
@@ -1,9 +1,9 @@
import React from 'react';
import {SvgProps} from 'react-native-svg';
-import emojis, {localeEmojis} from '../../assets/emojis';
-import Trie from './Trie';
+import emojis, {localeEmojis} from '@assets/emojis';
+import CONST from '@src/CONST';
import Timing from './actions/Timing';
-import CONST from '../CONST';
+import Trie from './Trie';
type Emoji = {
code: string;
diff --git a/src/libs/EmojiUtils.js b/src/libs/EmojiUtils.js
index 05ad1bd3c2ce..4ade70537b0b 100644
--- a/src/libs/EmojiUtils.js
+++ b/src/libs/EmojiUtils.js
@@ -1,14 +1,14 @@
-import _ from 'underscore';
import {getUnixTime} from 'date-fns';
import Str from 'expensify-common/lib/str';
-import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
import lodashMin from 'lodash/min';
import lodashSum from 'lodash/sum';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import * as Emojis from '@assets/emojis';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import emojisTrie from './EmojiTrie';
-import * as Emojis from '../../assets/emojis';
let frequentlyUsedEmojis = [];
Onyx.connect({
diff --git a/src/libs/Environment/Environment.js b/src/libs/Environment/Environment.js
index c039b49d33aa..e89c8d74a43a 100644
--- a/src/libs/Environment/Environment.js
+++ b/src/libs/Environment/Environment.js
@@ -1,8 +1,8 @@
-import Config from 'react-native-config';
import lodashGet from 'lodash/get';
-import CONST from '../../CONST';
+import Config from 'react-native-config';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
import getEnvironment from './getEnvironment';
-import CONFIG from '../../CONFIG';
const ENVIRONMENT_URLS = {
[CONST.ENVIRONMENT.DEV]: CONST.DEV_NEW_EXPENSIFY_URL + CONFIG.DEV_PORT,
diff --git a/src/libs/Environment/betaChecker/index.android.js b/src/libs/Environment/betaChecker/index.android.js
index e74648973c34..18a4290cb634 100644
--- a/src/libs/Environment/betaChecker/index.android.js
+++ b/src/libs/Environment/betaChecker/index.android.js
@@ -1,9 +1,9 @@
-import semver from 'semver';
import Onyx from 'react-native-onyx';
-import CONST from '../../../CONST';
+import semver from 'semver';
+import * as AppUpdate from '@userActions/AppUpdate';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import pkg from '../../../../package.json';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as AppUpdate from '../../actions/AppUpdate';
let isLastSavedBeta = false;
Onyx.connect({
diff --git a/src/libs/Environment/getEnvironment/index.js b/src/libs/Environment/getEnvironment/index.js
index a987678d6a6e..bc1c31cf5076 100644
--- a/src/libs/Environment/getEnvironment/index.js
+++ b/src/libs/Environment/getEnvironment/index.js
@@ -1,6 +1,6 @@
import lodashGet from 'lodash/get';
import Config from 'react-native-config';
-import CONST from '../../../CONST';
+import CONST from '@src/CONST';
/**
* Returns a promise that resolves with the current environment string value
diff --git a/src/libs/Environment/getEnvironment/index.native.js b/src/libs/Environment/getEnvironment/index.native.js
index 73014c4beffb..ca660f9117cb 100644
--- a/src/libs/Environment/getEnvironment/index.native.js
+++ b/src/libs/Environment/getEnvironment/index.native.js
@@ -1,7 +1,7 @@
import lodashGet from 'lodash/get';
import Config from 'react-native-config';
-import betaChecker from '../betaChecker';
-import CONST from '../../../CONST';
+import betaChecker from '@libs/Environment/betaChecker';
+import CONST from '@src/CONST';
let environment = null;
diff --git a/src/libs/ErrorUtils.ts b/src/libs/ErrorUtils.ts
index bf4fc0d810a4..99cd8f34b1e7 100644
--- a/src/libs/ErrorUtils.ts
+++ b/src/libs/ErrorUtils.ts
@@ -1,9 +1,9 @@
-import CONST from '../CONST';
+import CONST from '@src/CONST';
+import {TranslationFlatObject} from '@src/languages/types';
+import {ErrorFields, Errors} from '@src/types/onyx/OnyxCommon';
+import Response from '@src/types/onyx/Response';
import DateUtils from './DateUtils';
import * as Localize from './Localize';
-import Response from '../types/onyx/Response';
-import {ErrorFields, Errors} from '../types/onyx/OnyxCommon';
-import {TranslationFlatObject} from '../languages/types';
function getAuthenticateErrorMessage(response: Response): keyof TranslationFlatObject {
switch (response.jsonCode) {
diff --git a/src/libs/Firebase/index.native.ts b/src/libs/Firebase/index.native.ts
index 2014e2b8bd3e..107b3f8905b3 100644
--- a/src/libs/Firebase/index.native.ts
+++ b/src/libs/Firebase/index.native.ts
@@ -1,6 +1,6 @@
/* eslint-disable no-unused-vars */
import perf from '@react-native-firebase/perf';
-import * as Environment from '../Environment/Environment';
+import * as Environment from '@libs/Environment/Environment';
import {StartTrace, StopTrace, TraceMap} from './types';
const traceMap: TraceMap = {};
diff --git a/src/libs/Growl.ts b/src/libs/Growl.ts
index 33d7311973cb..55bcf88206e9 100644
--- a/src/libs/Growl.ts
+++ b/src/libs/Growl.ts
@@ -1,5 +1,5 @@
import React from 'react';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
type GrowlRef = {
show?: (bodyText: string, type: string, duration: number) => void;
diff --git a/src/libs/HeaderUtils.js b/src/libs/HeaderUtils.js
index 16d375ea1124..2edca95ecf74 100644
--- a/src/libs/HeaderUtils.js
+++ b/src/libs/HeaderUtils.js
@@ -1,7 +1,7 @@
-import * as Localize from './Localize';
-import * as Session from './actions/Session';
+import * as Expensicons from '@components/Icon/Expensicons';
import * as Report from './actions/Report';
-import * as Expensicons from '../components/Icon/Expensicons';
+import * as Session from './actions/Session';
+import * as Localize from './Localize';
/**
* @param {Object} report
diff --git a/src/libs/HttpUtils.js b/src/libs/HttpUtils.js
index 5a8185a03038..2df7421ea91c 100644
--- a/src/libs/HttpUtils.js
+++ b/src/libs/HttpUtils.js
@@ -1,10 +1,10 @@
import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import HttpsError from './Errors/HttpsError';
+import alert from '@components/Alert';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as ApiUtils from './ApiUtils';
-import alert from '../components/Alert';
+import HttpsError from './Errors/HttpsError';
let shouldFailAllRequests = false;
let shouldForceOffline = false;
diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts
index d8a916d0dfb0..ff4f2aafc8a8 100644
--- a/src/libs/IOUUtils.ts
+++ b/src/libs/IOUUtils.ts
@@ -1,7 +1,7 @@
-import CONST from '../CONST';
-import * as TransactionUtils from './TransactionUtils';
+import CONST from '@src/CONST';
+import {Report, Transaction} from '@src/types/onyx';
import * as CurrencyUtils from './CurrencyUtils';
-import {Report, Transaction} from '../types/onyx';
+import * as TransactionUtils from './TransactionUtils';
/**
* Calculates the amount per user given a list of participants
diff --git a/src/libs/IntlPolyfill/index.native.ts b/src/libs/IntlPolyfill/index.native.ts
index 9e578558faed..a044b4c52f0d 100644
--- a/src/libs/IntlPolyfill/index.native.ts
+++ b/src/libs/IntlPolyfill/index.native.ts
@@ -1,5 +1,5 @@
-import polyfillNumberFormat from './polyfillNumberFormat';
import polyfillListFormat from './polyfillListFormat';
+import polyfillNumberFormat from './polyfillNumberFormat';
import IntlPolyfill from './types';
/**
diff --git a/src/libs/IntlPolyfill/polyfillNumberFormat.ts b/src/libs/IntlPolyfill/polyfillNumberFormat.ts
index e4fdfef16e2c..1fac01958f05 100644
--- a/src/libs/IntlPolyfill/polyfillNumberFormat.ts
+++ b/src/libs/IntlPolyfill/polyfillNumberFormat.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
/**
* Check if the locale data is as expected on the device.
diff --git a/src/libs/KeyboardShortcut/KeyDownPressListener/index.js b/src/libs/KeyboardShortcut/KeyDownPressListener/index.js
deleted file mode 100644
index 4401beef1c59..000000000000
--- a/src/libs/KeyboardShortcut/KeyDownPressListener/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-function addKeyDownPressListner(callbackFunction) {
- document.addEventListener('keydown', callbackFunction);
-}
-
-function removeKeyDownPressListner(callbackFunction) {
- document.removeEventListener('keydown', callbackFunction);
-}
-
-export {addKeyDownPressListner, removeKeyDownPressListner};
diff --git a/src/libs/KeyboardShortcut/KeyDownPressListener/index.native.js b/src/libs/KeyboardShortcut/KeyDownPressListener/index.native.js
deleted file mode 100644
index aa1ded824d22..000000000000
--- a/src/libs/KeyboardShortcut/KeyDownPressListener/index.native.js
+++ /dev/null
@@ -1,4 +0,0 @@
-function addKeyDownPressListner() {}
-function removeKeyDownPressListner() {}
-
-export {addKeyDownPressListner, removeKeyDownPressListner};
diff --git a/src/libs/KeyboardShortcut/KeyDownPressListener/index.native.ts b/src/libs/KeyboardShortcut/KeyDownPressListener/index.native.ts
new file mode 100644
index 000000000000..8b460a069f05
--- /dev/null
+++ b/src/libs/KeyboardShortcut/KeyDownPressListener/index.native.ts
@@ -0,0 +1,6 @@
+import {AddKeyDownPressListener, RemoveKeyDownPressListener} from './types';
+
+const addKeyDownPressListener: AddKeyDownPressListener = () => {};
+const removeKeyDownPressListener: RemoveKeyDownPressListener = () => {};
+
+export {addKeyDownPressListener, removeKeyDownPressListener};
diff --git a/src/libs/KeyboardShortcut/KeyDownPressListener/index.ts b/src/libs/KeyboardShortcut/KeyDownPressListener/index.ts
new file mode 100644
index 000000000000..7e2b2a2ce319
--- /dev/null
+++ b/src/libs/KeyboardShortcut/KeyDownPressListener/index.ts
@@ -0,0 +1,11 @@
+import type {AddKeyDownPressListener, RemoveKeyDownPressListener} from './types';
+
+const addKeyDownPressListener: AddKeyDownPressListener = (callbackFunction) => {
+ document.addEventListener('keydown', callbackFunction);
+};
+
+const removeKeyDownPressListener: RemoveKeyDownPressListener = (callbackFunction) => {
+ document.removeEventListener('keydown', callbackFunction);
+};
+
+export {addKeyDownPressListener, removeKeyDownPressListener};
diff --git a/src/libs/KeyboardShortcut/KeyDownPressListener/types.ts b/src/libs/KeyboardShortcut/KeyDownPressListener/types.ts
new file mode 100644
index 000000000000..1e36051a794d
--- /dev/null
+++ b/src/libs/KeyboardShortcut/KeyDownPressListener/types.ts
@@ -0,0 +1,6 @@
+type KeyDownPressCallback = (event: KeyboardEvent) => void;
+
+type AddKeyDownPressListener = (callbackFunction: KeyDownPressCallback) => void;
+type RemoveKeyDownPressListener = (callbackFunction: KeyDownPressCallback) => void;
+
+export type {AddKeyDownPressListener, RemoveKeyDownPressListener};
diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js
deleted file mode 100644
index 7b1cb00a408b..000000000000
--- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import _ from 'underscore';
-import getKeyEventModifiers from '../getKeyEventModifiers';
-import isEnterWhileComposition from '../isEnterWhileComposition';
-
-/**
- * Checks if an event for that key is configured and if so, runs it.
- * @param {Function} getDisplayName
- * @param {Object} eventHandlers
- * @param {Object} keycommandEvent
- * @param {Event} event
- * @private
- */
-function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event) {
- if (!(event instanceof KeyboardEvent) || isEnterWhileComposition(event)) {
- return;
- }
-
- const eventModifiers = getKeyEventModifiers(keycommandEvent);
- const displayName = getDisplayName(keycommandEvent.input, eventModifiers);
-
- // Loop over all the callbacks
- _.every(eventHandlers[displayName], (callback) => {
- // Early return for excludedNodes
- if (_.contains(callback.excludedNodes, event.target.nodeName)) {
- return true;
- }
-
- // If configured to do so, prevent input text control to trigger this event
- if (!callback.captureOnInputs && (event.target.nodeName === 'INPUT' || event.target.nodeName === 'TEXTAREA' || event.target.contentEditable === 'true')) {
- return true;
- }
-
- // Determine if the event should bubble before executing the callback (which may have side-effects)
- let shouldBubble = callback.shouldBubble || false;
- if (_.isFunction(callback.shouldBubble)) {
- shouldBubble = callback.shouldBubble();
- }
-
- if (_.isFunction(callback.callback)) {
- callback.callback(event);
- }
- if (callback.shouldPreventDefault) {
- event.preventDefault();
- }
-
- // If the event should not bubble, short-circuit the loop
- return shouldBubble;
- });
-}
-
-export default bindHandlerToKeydownEvent;
diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js
deleted file mode 100644
index de59c819c504..000000000000
--- a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import _ from 'underscore';
-import getKeyEventModifiers from '../getKeyEventModifiers';
-
-/**
- * Checks if an event for that key is configured and if so, runs it.
- * @param {Function} getDisplayName
- * @param {Object} eventHandlers
- * @param {Object} keycommandEvent
- * @param {Event} event
- * @private
- */
-function bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event) {
- const eventModifiers = getKeyEventModifiers(keycommandEvent);
- const displayName = getDisplayName(keycommandEvent.input, eventModifiers);
-
- // Loop over all the callbacks
- _.every(eventHandlers[displayName], (callback) => {
- // Determine if the event should bubble before executing the callback (which may have side-effects)
- let shouldBubble = callback.shouldBubble || false;
- if (_.isFunction(callback.shouldBubble)) {
- shouldBubble = callback.shouldBubble();
- }
-
- if (_.isFunction(callback.callback)) {
- callback.callback(event);
- }
-
- // If the event should not bubble, short-circuit the loop
- return shouldBubble;
- });
-}
-
-export default bindHandlerToKeydownEvent;
diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts
new file mode 100644
index 000000000000..72a4365b87e2
--- /dev/null
+++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.native.ts
@@ -0,0 +1,28 @@
+import getKeyEventModifiers from '@libs/KeyboardShortcut/getKeyEventModifiers';
+import BindHandlerToKeydownEvent from './types';
+
+/**
+ * Checks if an event for that key is configured and if so, runs it.
+ */
+const bindHandlerToKeydownEvent: BindHandlerToKeydownEvent = (getDisplayName, eventHandlers, keyCommandEvent, event) => {
+ const eventModifiers = getKeyEventModifiers(keyCommandEvent);
+ const displayName = getDisplayName(keyCommandEvent.input, eventModifiers);
+
+ // 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)
+ let shouldBubble: boolean | (() => void) | void = callback.shouldBubble || false;
+ if (typeof callback.shouldBubble === 'function') {
+ shouldBubble = callback.shouldBubble();
+ }
+
+ if (typeof callback.callback === 'function') {
+ callback.callback(event);
+ }
+
+ // If the event should not bubble, short-circuit the loop
+ return shouldBubble;
+ });
+};
+
+export default bindHandlerToKeydownEvent;
diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.ts b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.ts
new file mode 100644
index 000000000000..8f2eaad25c5b
--- /dev/null
+++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/index.ts
@@ -0,0 +1,51 @@
+import getKeyEventModifiers from '@libs/KeyboardShortcut/getKeyEventModifiers';
+import isEnterWhileComposition from '@libs/KeyboardShortcut/isEnterWhileComposition';
+import BindHandlerToKeydownEvent from './types';
+
+/**
+ * Checks if an event for that key is configured and if so, runs it.
+ */
+const bindHandlerToKeydownEvent: BindHandlerToKeydownEvent = (getDisplayName, eventHandlers, keyCommandEvent, event) => {
+ if (!(event instanceof KeyboardEvent) || isEnterWhileComposition(event)) {
+ return;
+ }
+
+ const eventModifiers = getKeyEventModifiers(keyCommandEvent);
+ const displayName = getDisplayName(keyCommandEvent.input, eventModifiers);
+
+ // Loop over all the callbacks
+ Object.values(eventHandlers[displayName]).every((callback) => {
+ const textArea = event.target as HTMLTextAreaElement;
+ const contentEditable = textArea?.contentEditable;
+ const nodeName = textArea?.nodeName;
+
+ // Early return for excludedNodes
+ if (callback.excludedNodes.includes(nodeName)) {
+ return true;
+ }
+
+ // If configured to do so, prevent input text control to trigger this event
+ if (!callback.captureOnInputs && (nodeName === 'INPUT' || nodeName === 'TEXTAREA' || contentEditable === 'true')) {
+ return true;
+ }
+
+ // Determine if the event should bubble before executing the callback (which may have side-effects)
+ let shouldBubble: boolean | (() => void) | void = callback.shouldBubble || false;
+ if (typeof callback.shouldBubble === 'function') {
+ shouldBubble = callback.shouldBubble();
+ }
+
+ if (typeof callback.callback === 'function') {
+ callback.callback(event);
+ }
+
+ if (callback.shouldPreventDefault) {
+ event.preventDefault();
+ }
+
+ // If the event should not bubble, short-circuit the loop
+ return shouldBubble;
+ });
+};
+
+export default bindHandlerToKeydownEvent;
diff --git a/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/types.ts b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/types.ts
new file mode 100644
index 000000000000..2fe9521fa117
--- /dev/null
+++ b/src/libs/KeyboardShortcut/bindHandlerToKeydownEvent/types.ts
@@ -0,0 +1,11 @@
+import type {EventHandler} from '..';
+
+type KeyCommandEvent = {input: string; modifierFlags?: string};
+
+type GetDisplayName = (key: string, modifiers: string | string[]) => string;
+
+type BindHandlerToKeydownEvent = (getDisplayName: GetDisplayName, eventHandlers: Record, keyCommandEvent: KeyCommandEvent, event: KeyboardEvent) => void;
+
+export default BindHandlerToKeydownEvent;
+
+export type {KeyCommandEvent};
diff --git a/src/libs/KeyboardShortcut/getKeyEventModifiers.js b/src/libs/KeyboardShortcut/getKeyEventModifiers.js
deleted file mode 100644
index 7865d51a0507..000000000000
--- a/src/libs/KeyboardShortcut/getKeyEventModifiers.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import * as KeyCommand from 'react-native-key-command';
-import lodashGet from 'lodash/get';
-
-/**
- * Gets modifiers from a keyboard event.
- *
- * @param {Event} event
- * @returns {Array}
- */
-function getKeyEventModifiers(event) {
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierControl', 'keyModifierControl')) {
- return ['CONTROL'];
- }
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierCommand', 'keyModifierCommand')) {
- return ['META'];
- }
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierShiftControl', 'keyModifierShiftControl')) {
- return ['CONTROL', 'Shift'];
- }
- if (event.modifierFlags === lodashGet(KeyCommand, 'constants.keyModifierShiftCommand', 'keyModifierShiftCommand')) {
- return ['META', 'Shift'];
- }
-
- return [];
-}
-
-export default getKeyEventModifiers;
diff --git a/src/libs/KeyboardShortcut/getKeyEventModifiers.ts b/src/libs/KeyboardShortcut/getKeyEventModifiers.ts
new file mode 100644
index 000000000000..f82de725bb50
--- /dev/null
+++ b/src/libs/KeyboardShortcut/getKeyEventModifiers.ts
@@ -0,0 +1,29 @@
+import * as KeyCommand from 'react-native-key-command';
+import {KeyCommandEvent} from './bindHandlerToKeydownEvent/types';
+
+const keyModifierControl = KeyCommand?.constants.keyModifierControl ?? 'keyModifierControl';
+const keyModifierCommand = KeyCommand?.constants.keyModifierCommand ?? 'keyModifierCommand';
+const keyModifierShiftControl = KeyCommand?.constants.keyModifierShiftControl ?? 'keyModifierShiftControl';
+const keyModifierShiftCommand = KeyCommand?.constants.keyModifierShiftCommand ?? 'keyModifierShiftCommand';
+
+/**
+ * Gets modifiers from a keyboard event.
+ */
+function getKeyEventModifiers(event: KeyCommandEvent): string[] {
+ if (event.modifierFlags === keyModifierControl) {
+ return ['CONTROL'];
+ }
+ if (event.modifierFlags === keyModifierCommand) {
+ return ['META'];
+ }
+ if (event.modifierFlags === keyModifierShiftControl) {
+ return ['CONTROL', 'Shift'];
+ }
+ if (event.modifierFlags === keyModifierShiftCommand) {
+ return ['META', 'Shift'];
+ }
+
+ return [];
+}
+
+export default getKeyEventModifiers;
diff --git a/src/libs/KeyboardShortcut/index.js b/src/libs/KeyboardShortcut/index.js
deleted file mode 100644
index bce65744801c..000000000000
--- a/src/libs/KeyboardShortcut/index.js
+++ /dev/null
@@ -1,172 +0,0 @@
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
-import * as KeyCommand from 'react-native-key-command';
-import bindHandlerToKeydownEvent from './bindHandlerToKeydownEvent';
-import getOperatingSystem from '../getOperatingSystem';
-import CONST from '../../CONST';
-
-const operatingSystem = getOperatingSystem();
-
-// Handlers for the various keyboard listeners we set up
-const eventHandlers = {};
-
-// Documentation information for keyboard shortcuts that are displayed in the keyboard shortcuts informational modal
-const documentedShortcuts = {};
-
-/**
- * @returns {Array}
- */
-function getDocumentedShortcuts() {
- return _.sortBy(_.values(documentedShortcuts), 'displayName');
-}
-
-/**
- * Generates the normalized display name for keyboard shortcuts.
- *
- * @param {String} key
- * @param {String|Array} modifiers
- * @returns {String}
- */
-function getDisplayName(key, modifiers) {
- let displayName = (() => {
- // Type of key is string and the type of KeyCommand.constants.* is number | string. Use _.isEqual to match different types.
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputEnter', 'keyInputEnter').toString().toLowerCase())) {
- return ['ENTER'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputEscape', 'keyInputEscape').toString().toLowerCase())) {
- return ['ESCAPE'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputUpArrow', 'keyInputUpArrow').toString().toLowerCase())) {
- return ['ARROWUP'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputDownArrow', 'keyInputDownArrow').toString().toLowerCase())) {
- return ['ARROWDOWN'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputLeftArrow', 'keyInputLeftArrow').toString().toLowerCase())) {
- return ['ARROWLEFT'];
- }
- if (_.isEqual(key.toLowerCase(), lodashGet(KeyCommand, 'constants.keyInputRightArrow', 'keyInputRightArrow').toString().toLowerCase())) {
- return ['ARROWRIGHT'];
- }
- return [key.toUpperCase()];
- })();
-
- if (_.isString(modifiers)) {
- displayName.unshift(modifiers);
- } else if (_.isArray(modifiers)) {
- displayName = [..._.sortBy(modifiers), ...displayName];
- }
-
- displayName = _.map(displayName, (modifier) => lodashGet(CONST.KEYBOARD_SHORTCUT_KEY_DISPLAY_NAME, modifier.toUpperCase(), modifier));
-
- return displayName.join(' + ');
-}
-
-_.each(CONST.KEYBOARD_SHORTCUTS, (shortcut) => {
- const shortcutTrigger = lodashGet(shortcut, ['trigger', operatingSystem], lodashGet(shortcut, 'trigger.DEFAULT'));
-
- // If there is no trigger for the current OS nor a default trigger, then we don't need to do anything
- if (!shortcutTrigger) {
- return;
- }
-
- KeyCommand.addListener(shortcutTrigger, (keycommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keycommandEvent, event));
-});
-
-/**
- * Unsubscribes a keyboard event handler.
- *
- * @param {String} displayName The display name for the key combo to stop watching
- * @param {String} callbackID The specific ID given to the callback at the time it was added
- * @private
- */
-function unsubscribe(displayName, callbackID) {
- eventHandlers[displayName] = _.reject(eventHandlers[displayName], (callback) => callback.id === callbackID);
- if (_.has(documentedShortcuts, displayName) && _.size(eventHandlers[displayName]) === 0) {
- delete documentedShortcuts[displayName];
- }
-}
-
-/**
- * Return platform specific modifiers for keys like Control (CMD on macOS)
- *
- * @param {Array} keys
- * @returns {Array}
- */
-function getPlatformEquivalentForKeys(keys) {
- return _.map(keys, (key) => {
- if (!_.has(CONST.PLATFORM_SPECIFIC_KEYS, key)) {
- return key;
- }
-
- const platformModifiers = CONST.PLATFORM_SPECIFIC_KEYS[key];
- return lodashGet(platformModifiers, operatingSystem, platformModifiers.DEFAULT || key);
- });
-}
-
-/**
- * Subscribes to a keyboard event.
- * @param {String} key The key to watch, i.e. 'K' or 'Escape'
- * @param {Function} callback The callback to call
- * @param {String} descriptionKey Translation key for shortcut description
- * @param {Array} [modifiers] Can either be shift or control
- * @param {Boolean} [captureOnInputs] Should we capture the event on inputs too?
- * @param {Boolean|Function} [shouldBubble] Should the event bubble?
- * @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)
- * @returns {Function} clean up method
- */
-function subscribe(key, callback, descriptionKey, modifiers = 'shift', captureOnInputs = false, shouldBubble = false, priority = 0, shouldPreventDefault = true, excludedNodes = []) {
- const platformAdjustedModifiers = getPlatformEquivalentForKeys(modifiers);
- const displayName = getDisplayName(key, platformAdjustedModifiers);
- if (!_.has(eventHandlers, displayName)) {
- eventHandlers[displayName] = [];
- }
-
- const callbackID = Str.guid();
- eventHandlers[displayName].splice(priority, 0, {
- id: callbackID,
- callback,
- captureOnInputs,
- shouldPreventDefault,
- shouldBubble,
- excludedNodes,
- });
-
- if (descriptionKey) {
- documentedShortcuts[displayName] = {
- shortcutKey: key,
- descriptionKey,
- displayName,
- modifiers,
- };
- }
-
- return () => unsubscribe(displayName, callbackID);
-}
-
-/**
- * This module configures a global keyboard event handler.
- *
- * It uses a stack to store event handlers for each key combination. Some additional details:
- *
- * - By default, new handlers are pushed to the top of the stack. If you pass a >0 priority when subscribing to the key event,
- * then the handler will get pushed further down the stack. This means that priority of 0 is higher than priority 1.
- *
- * - When a key event occurs, we trigger callbacks for that key starting from the top of the stack.
- * By default, events do not bubble, and only the handler at the top of the stack will be executed.
- * Individual callbacks can be configured with the shouldBubble parameter, to allow the next event handler on the stack execute.
- *
- * - Each handler has a unique callbackID, so calling the `unsubscribe` function (returned from `subscribe`) will unsubscribe the expected handler,
- * regardless of its position in the stack.
- */
-const KeyboardShortcut = {
- subscribe,
- getDisplayName,
- getDocumentedShortcuts,
- getPlatformEquivalentForKeys,
-};
-
-export default KeyboardShortcut;
diff --git a/src/libs/KeyboardShortcut/index.ts b/src/libs/KeyboardShortcut/index.ts
new file mode 100644
index 000000000000..249311f92cd2
--- /dev/null
+++ b/src/libs/KeyboardShortcut/index.ts
@@ -0,0 +1,190 @@
+import Str from 'expensify-common/lib/str';
+import * as KeyCommand from 'react-native-key-command';
+import getOperatingSystem from '@libs/getOperatingSystem';
+import CONST from '@src/CONST';
+import bindHandlerToKeydownEvent from './bindHandlerToKeydownEvent';
+
+const operatingSystem = getOperatingSystem();
+
+type EventHandler = {
+ id: string;
+ callback: (event?: KeyboardEvent) => void;
+ captureOnInputs: boolean;
+ shouldPreventDefault: boolean;
+ shouldBubble: boolean | (() => void);
+ excludedNodes: string[];
+};
+
+// Handlers for the various keyboard listeners we set up
+const eventHandlers: Record = {};
+
+type Shortcut = {
+ displayName: string;
+ shortcutKey: string;
+ descriptionKey: string;
+ modifiers: string[];
+};
+
+// Documentation information for keyboard shortcuts that are displayed in the keyboard shortcuts informational modal
+const documentedShortcuts: Record = {};
+
+function getDocumentedShortcuts(): Shortcut[] {
+ return Object.values(documentedShortcuts).sort((a, b) => a.displayName.localeCompare(b.displayName));
+}
+
+const keyInputEnter = KeyCommand?.constants?.keyInputEnter?.toString() ?? 'keyInputEnter';
+const keyInputEscape = KeyCommand?.constants?.keyInputEscape?.toString() ?? 'keyInputEscape';
+const keyInputUpArrow = KeyCommand?.constants?.keyInputUpArrow?.toString() ?? 'keyInputUpArrow';
+const keyInputDownArrow = KeyCommand?.constants?.keyInputDownArrow?.toString() ?? 'keyInputDownArrow';
+const keyInputLeftArrow = KeyCommand?.constants?.keyInputLeftArrow?.toString() ?? 'keyInputLeftArrow';
+const keyInputRightArrow = KeyCommand?.constants?.keyInputRightArrow?.toString() ?? 'keyInputRightArrow';
+
+/**
+ * Generates the normalized display name for keyboard shortcuts.
+ */
+function getDisplayName(key: string, modifiers: string | string[]): string {
+ let displayName = (() => {
+ // Type of key is string and the type of KeyCommand.constants.* is number | string.
+ if (key.toLowerCase() === keyInputEnter.toLowerCase()) {
+ return ['ENTER'];
+ }
+ if (key.toLowerCase() === keyInputEscape.toLowerCase()) {
+ return ['ESCAPE'];
+ }
+ if (key.toLowerCase() === keyInputUpArrow.toLowerCase()) {
+ return ['ARROWUP'];
+ }
+ if (key.toLowerCase() === keyInputDownArrow.toLowerCase()) {
+ return ['ARROWDOWN'];
+ }
+ if (key.toLowerCase() === keyInputLeftArrow.toLowerCase()) {
+ return ['ARROWLEFT'];
+ }
+ if (key.toLowerCase() === keyInputRightArrow.toLowerCase()) {
+ return ['ARROWRIGHT'];
+ }
+ return [key.toUpperCase()];
+ })();
+
+ if (typeof modifiers === 'string') {
+ displayName.unshift(modifiers);
+ } else if (Array.isArray(modifiers)) {
+ displayName = [...modifiers.sort(), ...displayName];
+ }
+
+ displayName = displayName.map((modifier) => CONST.KEYBOARD_SHORTCUT_KEY_DISPLAY_NAME[modifier.toUpperCase() as keyof typeof CONST.KEYBOARD_SHORTCUT_KEY_DISPLAY_NAME] ?? modifier);
+
+ return displayName.join(' + ');
+}
+
+Object.values(CONST.KEYBOARD_SHORTCUTS).forEach((shortcut) => {
+ // If there is no trigger for the current OS nor a default trigger, then we don't need to do anything
+ if (!('trigger' in shortcut)) {
+ return;
+ }
+
+ const shortcutTrigger = (operatingSystem && shortcut.trigger[operatingSystem as keyof typeof shortcut.trigger]) ?? shortcut.trigger.DEFAULT;
+
+ KeyCommand.addListener(shortcutTrigger, (keyCommandEvent, event) => bindHandlerToKeydownEvent(getDisplayName, eventHandlers, keyCommandEvent, event));
+});
+
+/**
+ * Unsubscribes a keyboard event handler.
+ */
+function unsubscribe(displayName: string, callbackID: string) {
+ eventHandlers[displayName] = eventHandlers[displayName].filter((callback) => callback.id !== callbackID);
+ if (eventHandlers[displayName]?.length === 0) {
+ delete documentedShortcuts[displayName];
+ }
+}
+
+/**
+ * Return platform specific modifiers for keys like Control (CMD on macOS)
+ */
+function getPlatformEquivalentForKeys(keys: string[]): string[] {
+ return keys.map((key) => {
+ if (!(key in CONST.PLATFORM_SPECIFIC_KEYS)) {
+ return key;
+ }
+
+ const platformModifiers = CONST.PLATFORM_SPECIFIC_KEYS[key as keyof typeof CONST.PLATFORM_SPECIFIC_KEYS];
+ return platformModifiers?.[operatingSystem as keyof typeof platformModifiers] ?? platformModifiers.DEFAULT ?? key;
+ });
+}
+
+/**
+ * Subscribes to a keyboard event.
+ * @param key The key to watch, i.e. 'K' or 'Escape'
+ * @param callback The callback to call
+ * @param descriptionKey Translation key for shortcut description
+ * @param [modifiers] Can either be shift or control
+ * @param [captureOnInputs] Should we capture the event on inputs too?
+ * @param [shouldBubble] Should the event bubble?
+ * @param [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 [shouldPreventDefault] Should call event.preventDefault after callback?
+ * @param [excludedNodes] Do not capture key events targeting excluded nodes (i.e. do not prevent default and let the event bubble)
+ * @returns clean up method
+ */
+function subscribe(
+ key: string,
+ callback: () => void,
+ descriptionKey: string,
+ modifiers: string[] = ['shift'],
+ captureOnInputs = false,
+ shouldBubble = false,
+ priority = 0,
+ shouldPreventDefault = true,
+ excludedNodes = [],
+) {
+ const platformAdjustedModifiers = getPlatformEquivalentForKeys(modifiers);
+ const displayName = getDisplayName(key, platformAdjustedModifiers);
+ if (!eventHandlers[displayName]) {
+ eventHandlers[displayName] = [];
+ }
+
+ const callbackID = Str.guid();
+ eventHandlers[displayName].splice(priority, 0, {
+ id: callbackID,
+ callback,
+ captureOnInputs,
+ shouldPreventDefault,
+ shouldBubble,
+ excludedNodes,
+ });
+
+ if (descriptionKey) {
+ documentedShortcuts[displayName] = {
+ shortcutKey: key,
+ descriptionKey,
+ displayName,
+ modifiers,
+ };
+ }
+
+ return () => unsubscribe(displayName, callbackID);
+}
+
+/**
+ * This module configures a global keyboard event handler.
+ *
+ * It uses a stack to store event handlers for each key combination. Some additional details:
+ *
+ * - By default, new handlers are pushed to the top of the stack. If you pass a >0 priority when subscribing to the key event,
+ * then the handler will get pushed further down the stack. This means that priority of 0 is higher than priority 1.
+ *
+ * - When a key event occurs, we trigger callbacks for that key starting from the top of the stack.
+ * By default, events do not bubble, and only the handler at the top of the stack will be executed.
+ * Individual callbacks can be configured with the shouldBubble parameter, to allow the next event handler on the stack execute.
+ *
+ * - Each handler has a unique callbackID, so calling the `unsubscribe` function (returned from `subscribe`) will unsubscribe the expected handler,
+ * regardless of its position in the stack.
+ */
+const KeyboardShortcut = {
+ subscribe,
+ getDisplayName,
+ getDocumentedShortcuts,
+ getPlatformEquivalentForKeys,
+};
+
+export default KeyboardShortcut;
+export type {EventHandler};
diff --git a/src/libs/KeyboardShortcut/isEnterWhileComposition.js b/src/libs/KeyboardShortcut/isEnterWhileComposition.ts
similarity index 73%
rename from src/libs/KeyboardShortcut/isEnterWhileComposition.js
rename to src/libs/KeyboardShortcut/isEnterWhileComposition.ts
index 6269440716b5..51e198f1c2d1 100644
--- a/src/libs/KeyboardShortcut/isEnterWhileComposition.js
+++ b/src/libs/KeyboardShortcut/isEnterWhileComposition.ts
@@ -1,13 +1,12 @@
-import * as Browser from '../Browser';
-import CONST from '../../CONST';
+import {NativeSyntheticEvent} from 'react-native';
+import * as Browser from '@libs/Browser';
+import CONST from '@src/CONST';
/**
* Check if the Enter key was pressed during IME confirmation (i.e. while the text is being composed).
* See {@link https://en.wikipedia.org/wiki/Input_method}
- * @param {Event} event
- * @returns {boolean}
*/
-const isEnterWhileComposition = (event) => {
+const isEnterWhileComposition = (event: KeyboardEvent): boolean => {
// if on mobile chrome, the enter key event is never fired when the enter key is pressed while composition.
if (Browser.isMobileChrome()) {
return false;
@@ -18,7 +17,8 @@ const isEnterWhileComposition = (event) => {
if (CONST.BROWSER.SAFARI === Browser.getBrowser()) {
return event.keyCode === 229;
}
- return event.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && event.nativeEvent && event.nativeEvent.isComposing;
+
+ return event.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey && (event as unknown as NativeSyntheticEvent)?.nativeEvent?.isComposing;
};
export default isEnterWhileComposition;
diff --git a/src/libs/LocaleDigitUtils.ts b/src/libs/LocaleDigitUtils.ts
index e17620aa5427..d9ba23ff4f9f 100644
--- a/src/libs/LocaleDigitUtils.ts
+++ b/src/libs/LocaleDigitUtils.ts
@@ -1,5 +1,4 @@
import _ from 'lodash';
-
import * as NumberFormatUtils from './NumberFormatUtils';
const STANDARD_DIGITS = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '-', ','];
diff --git a/src/libs/LocalePhoneNumber.ts b/src/libs/LocalePhoneNumber.ts
index 962040aee049..e50f3be87c84 100644
--- a/src/libs/LocalePhoneNumber.ts
+++ b/src/libs/LocalePhoneNumber.ts
@@ -1,7 +1,7 @@
-import Onyx from 'react-native-onyx';
-import Str from 'expensify-common/lib/str';
import {parsePhoneNumber} from 'awesome-phonenumber';
-import ONYXKEYS from '../ONYXKEYS';
+import Str from 'expensify-common/lib/str';
+import Onyx from 'react-native-onyx';
+import ONYXKEYS from '@src/ONYXKEYS';
let countryCodeByIP: number;
Onyx.connect({
diff --git a/src/libs/Localize/LocaleListener/BaseLocaleListener.js b/src/libs/Localize/LocaleListener/BaseLocaleListener.js
index 9d4e62c374b0..0f861b20040a 100644
--- a/src/libs/Localize/LocaleListener/BaseLocaleListener.js
+++ b/src/libs/Localize/LocaleListener/BaseLocaleListener.js
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import CONST from '../../../CONST';
-import ONYXKEYS from '../../../ONYXKEYS';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
let preferredLocale = CONST.LOCALES.DEFAULT;
diff --git a/src/libs/Localize/index.js b/src/libs/Localize/index.js
index a26c7d4ebc10..f2f8cfa1f8b0 100644
--- a/src/libs/Localize/index.js
+++ b/src/libs/Localize/index.js
@@ -1,15 +1,15 @@
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
import * as RNLocalize from 'react-native-localize';
import Onyx from 'react-native-onyx';
-import Log from '../Log';
-import Config from '../../CONFIG';
-import translations from '../../languages/translations';
-import CONST from '../../CONST';
+import _ from 'underscore';
+import Log from '@libs/Log';
+import Config from '@src/CONFIG';
+import CONST from '@src/CONST';
+import translations from '@src/languages/translations';
+import ONYXKEYS from '@src/ONYXKEYS';
import LocaleListener from './LocaleListener';
import BaseLocaleListener from './LocaleListener/BaseLocaleListener';
-import ONYXKEYS from '../../ONYXKEYS';
// Current user mail is needed for handling missing translations
let userEmail = '';
diff --git a/src/libs/Log.ts b/src/libs/Log.ts
index cf139eec2682..e171e6338ffe 100644
--- a/src/libs/Log.ts
+++ b/src/libs/Log.ts
@@ -1,12 +1,13 @@
// Making an exception to this rule here since we don't need an "action" for Log and Log should just be used directly. Creating a Log
// action would likely cause confusion about which one to use. But most other API methods should happen inside an action file.
+
/* eslint-disable rulesdir/no-api-in-views */
-import {Merge} from 'type-fest';
import Logger from 'expensify-common/lib/Logger';
-import getPlatform from './getPlatform';
+import {Merge} from 'type-fest';
import pkg from '../../package.json';
-import requireParameters from './requireParameters';
+import getPlatform from './getPlatform';
import * as Network from './Network';
+import requireParameters from './requireParameters';
let timeout: NodeJS.Timeout;
diff --git a/src/libs/LoginUtils.ts b/src/libs/LoginUtils.ts
index 32f6aece6f96..742f9bfe16ce 100644
--- a/src/libs/LoginUtils.ts
+++ b/src/libs/LoginUtils.ts
@@ -1,9 +1,9 @@
+import {parsePhoneNumber} from 'awesome-phonenumber';
+import {PUBLIC_DOMAINS} from 'expensify-common/lib/CONST';
import Str from 'expensify-common/lib/str';
import Onyx from 'react-native-onyx';
-import {PUBLIC_DOMAINS} from 'expensify-common/lib/CONST';
-import {parsePhoneNumber} from 'awesome-phonenumber';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
let countryCodeByIP: number;
Onyx.connect({
diff --git a/src/libs/Metrics/index.native.ts b/src/libs/Metrics/index.native.ts
index 526e5c57a269..373f826e9ca3 100644
--- a/src/libs/Metrics/index.native.ts
+++ b/src/libs/Metrics/index.native.ts
@@ -1,4 +1,4 @@
-import CONFIG from '../../CONFIG';
+import CONFIG from '@src/CONFIG';
import {CanCaptureOnyxMetrics, CanCapturePerformanceMetrics} from './types';
/**
diff --git a/src/libs/Metrics/index.ts b/src/libs/Metrics/index.ts
index 7c33f31cb19e..1097826aff24 100644
--- a/src/libs/Metrics/index.ts
+++ b/src/libs/Metrics/index.ts
@@ -1,4 +1,4 @@
-import CONFIG from '../../CONFIG';
+import CONFIG from '@src/CONFIG';
import {CanCaptureOnyxMetrics, CanCapturePerformanceMetrics} from './types';
// We don't capture performance metrics on web as there are enough tools available
diff --git a/src/libs/Middleware/HandleUnusedOptimisticID.ts b/src/libs/Middleware/HandleUnusedOptimisticID.ts
index 14f7d08d1fdb..abca86522d2b 100644
--- a/src/libs/Middleware/HandleUnusedOptimisticID.ts
+++ b/src/libs/Middleware/HandleUnusedOptimisticID.ts
@@ -1,9 +1,9 @@
import _ from 'lodash';
-import ONYXKEYS from '../../ONYXKEYS';
-import Report from '../../types/onyx/Report';
-import {Middleware} from '../Request';
-import * as PersistedRequests from '../actions/PersistedRequests';
-import deepReplaceKeysAndValues from '../deepReplaceKeysAndValues';
+import deepReplaceKeysAndValues from '@libs/deepReplaceKeysAndValues';
+import {Middleware} from '@libs/Request';
+import * as PersistedRequests from '@userActions/PersistedRequests';
+import ONYXKEYS from '@src/ONYXKEYS';
+import Report from '@src/types/onyx/Report';
const handleUnusedOptimisticID: Middleware = (requestResponse, request, isFromSequentialQueue) =>
requestResponse.then((response) => {
diff --git a/src/libs/Middleware/Logging.ts b/src/libs/Middleware/Logging.ts
index 171cb4b9ab4c..3ef819298f80 100644
--- a/src/libs/Middleware/Logging.ts
+++ b/src/libs/Middleware/Logging.ts
@@ -1,7 +1,7 @@
-import Log from '../Log';
-import CONST from '../../CONST';
-import Request from '../../types/onyx/Request';
-import Response from '../../types/onyx/Response';
+import Log from '@libs/Log';
+import CONST from '@src/CONST';
+import Request from '@src/types/onyx/Request';
+import Response from '@src/types/onyx/Response';
import Middleware from './types';
function logRequestDetails(message: string, request: Request, response?: Response | void) {
diff --git a/src/libs/Middleware/Reauthentication.ts b/src/libs/Middleware/Reauthentication.ts
index aec09227e441..f1f71a85b16c 100644
--- a/src/libs/Middleware/Reauthentication.ts
+++ b/src/libs/Middleware/Reauthentication.ts
@@ -1,10 +1,10 @@
-import CONST from '../../CONST';
-import * as NetworkStore from '../Network/NetworkStore';
-import * as MainQueue from '../Network/MainQueue';
-import * as Authentication from '../Authentication';
-import * as Request from '../Request';
-import Log from '../Log';
-import NetworkConnection from '../NetworkConnection';
+import * as Authentication from '@libs/Authentication';
+import Log from '@libs/Log';
+import * as MainQueue from '@libs/Network/MainQueue';
+import * as NetworkStore from '@libs/Network/NetworkStore';
+import NetworkConnection from '@libs/NetworkConnection';
+import * as Request from '@libs/Request';
+import CONST from '@src/CONST';
import Middleware from './types';
// We store a reference to the active authentication request so that we are only ever making one request to authenticate at a time.
diff --git a/src/libs/Middleware/RecheckConnection.ts b/src/libs/Middleware/RecheckConnection.ts
index 5a685d66fd02..1f43b0171800 100644
--- a/src/libs/Middleware/RecheckConnection.ts
+++ b/src/libs/Middleware/RecheckConnection.ts
@@ -1,5 +1,5 @@
-import CONST from '../../CONST';
-import NetworkConnection from '../NetworkConnection';
+import NetworkConnection from '@libs/NetworkConnection';
+import CONST from '@src/CONST';
import Middleware from './types';
/**
diff --git a/src/libs/Middleware/SaveResponseInOnyx.ts b/src/libs/Middleware/SaveResponseInOnyx.ts
index 0a279a7425b4..d73a10d98663 100644
--- a/src/libs/Middleware/SaveResponseInOnyx.ts
+++ b/src/libs/Middleware/SaveResponseInOnyx.ts
@@ -1,7 +1,7 @@
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as MemoryOnlyKeys from '../actions/MemoryOnlyKeys/MemoryOnlyKeys';
-import * as OnyxUpdates from '../actions/OnyxUpdates';
+import * as MemoryOnlyKeys from '@userActions/MemoryOnlyKeys/MemoryOnlyKeys';
+import * as OnyxUpdates from '@userActions/OnyxUpdates';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import Middleware from './types';
// If we're executing any of these requests, we don't need to trigger our OnyxUpdates flow to update the current data even if our current value is out of
diff --git a/src/libs/Middleware/types.ts b/src/libs/Middleware/types.ts
index ece210ffe2af..c1d199539b15 100644
--- a/src/libs/Middleware/types.ts
+++ b/src/libs/Middleware/types.ts
@@ -1,5 +1,5 @@
-import Request from '../../types/onyx/Request';
-import Response from '../../types/onyx/Response';
+import Request from '@src/types/onyx/Request';
+import Response from '@src/types/onyx/Response';
type Middleware = (response: Promise, request: Request, isFromSequentialQueue: boolean) => Promise;
diff --git a/src/libs/MoneyRequestUtils.ts b/src/libs/MoneyRequestUtils.ts
index 420184973a34..83c66be429d2 100644
--- a/src/libs/MoneyRequestUtils.ts
+++ b/src/libs/MoneyRequestUtils.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
/**
* Strip comma from the amount
diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js
index dd7175dbc6f6..34837135d22d 100644
--- a/src/libs/Navigation/AppNavigator/AuthScreens.js
+++ b/src/libs/Navigation/AppNavigator/AuthScreens.js
@@ -1,41 +1,46 @@
-import React from 'react';
-import Onyx, {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {memo, useEffect, useRef} from 'react';
import {View} from 'react-native';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import CONST from '../../../CONST';
-import compose from '../../compose';
-import * as PersonalDetails from '../../actions/PersonalDetails';
-import * as Pusher from '../../Pusher/pusher';
-import PusherConnectionManager from '../../PusherConnectionManager';
-import ROUTES from '../../../ROUTES';
-import ONYXKEYS from '../../../ONYXKEYS';
-import Timing from '../../actions/Timing';
-import NetworkConnection from '../../NetworkConnection';
-import CONFIG from '../../../CONFIG';
-import KeyboardShortcut from '../../KeyboardShortcut';
-import Navigation from '../Navigation';
-import * as User from '../../actions/User';
-import * as Modal from '../../actions/Modal';
-import * as Report from '../../actions/Report';
+import Onyx, {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import getCurrentUrl from '@libs/Navigation/currentUrl';
+import Navigation from '@libs/Navigation/Navigation';
+import NetworkConnection from '@libs/NetworkConnection';
+import * as Pusher from '@libs/Pusher/pusher';
+import PusherConnectionManager from '@libs/PusherConnectionManager';
+import * as SessionUtils from '@libs/SessionUtils';
+import DemoSetupPage from '@pages/DemoSetupPage';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import DesktopSignInRedirectPage from '@pages/signin/DesktopSignInRedirectPage';
+import styles from '@styles/styles';
+import * as App from '@userActions/App';
+import * as Download from '@userActions/Download';
+import * as Modal from '@userActions/Modal';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import * as Report from '@userActions/Report';
+import * as Session from '@userActions/Session';
+import Timing from '@userActions/Timing';
+import * as User from '@userActions/User';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import NAVIGATORS from '@src/NAVIGATORS';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
import createCustomStackNavigator from './createCustomStackNavigator';
-import SCREENS from '../../../SCREENS';
import defaultScreenOptions from './defaultScreenOptions';
-import * as App from '../../actions/App';
-import * as Download from '../../actions/Download';
-import * as Session from '../../actions/Session';
-import RightModalNavigator from './Navigators/RightModalNavigator';
-import CentralPaneNavigator from './Navigators/CentralPaneNavigator';
-import NAVIGATORS from '../../../NAVIGATORS';
-import DesktopSignInRedirectPage from '../../../pages/signin/DesktopSignInRedirectPage';
-import styles from '../../../styles/styles';
-import * as SessionUtils from '../../SessionUtils';
-import NotFoundPage from '../../../pages/ErrorPage/NotFoundPage';
import getRootNavigatorScreenOptions from './getRootNavigatorScreenOptions';
-import DemoSetupPage from '../../../pages/DemoSetupPage';
-import getCurrentUrl from '../currentUrl';
+import CentralPaneNavigator from './Navigators/CentralPaneNavigator';
+import RightModalNavigator from './Navigators/RightModalNavigator';
+
+const loadReportAttachments = () => require('../../../pages/home/report/ReportAttachments').default;
+const loadSidebarScreen = () => require('../../../pages/home/sidebar/SidebarScreen').default;
+const loadValidateLoginPage = () => require('../../../pages/ValidateLoginPage').default;
+const loadLogOutPreviousUserPage = () => require('../../../pages/LogOutPreviousUserPage').default;
+const loadConciergePage = () => require('../../../pages/ConciergePage').default;
let timezone;
let currentAccountID;
@@ -89,11 +94,11 @@ Onyx.connect({
});
const RootStack = createCustomStackNavigator();
-
// We want to delay the re-rendering for components(e.g. ReportActionCompose)
// that depends on modal visibility until Modal is completely closed and its focused
// When modal screen is focused, update modal visibility in Onyx
// https://reactnavigation.org/docs/navigation-events/
+
const modalScreenListeners = {
focus: () => {
Modal.setModalVisibility(true);
@@ -124,8 +129,6 @@ const propTypes = {
isBeginningDemo: PropTypes.bool,
}),
}),
-
- ...windowDimensionsPropTypes,
};
const defaultProps = {
@@ -138,16 +141,23 @@ const defaultProps = {
demoInfo: {},
};
-class AuthScreens extends React.Component {
- constructor(props) {
- super(props);
+function AuthScreens({isUsingMemoryOnlyKeys, lastUpdateIDAppliedToClient, session, lastOpenedPublicRoomID, demoInfo}) {
+ const {isSmallScreenWidth} = useWindowDimensions();
+ const screenOptions = getRootNavigatorScreenOptions(isSmallScreenWidth);
+ const isInitialRender = useRef(true);
+ if (isInitialRender.current) {
Timing.start(CONST.TIMING.HOMEPAGE_INITIAL_RENDER);
+ isInitialRender.current = false;
}
- componentDidMount() {
+ useEffect(() => {
+ const shortcutsOverviewShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUTS;
+ const searchShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SEARCH;
+ const chatShortcutConfig = CONST.KEYBOARD_SHORTCUTS.NEW_CHAT;
+ const shouldGetAllData = isUsingMemoryOnlyKeys || SessionUtils.didUserLogInDuringSession();
const currentUrl = getCurrentUrl();
- const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(currentUrl, this.props.session.email);
+ const isLoggingInAsNewUser = SessionUtils.isLoggingInAsNewUser(currentUrl, session.email);
// Sign out the current user if we're transitioning with a different user
const isTransitioning = currentUrl.includes(ROUTES.TRANSITION_BETWEEN_APPS);
if (isLoggingInAsNewUser && isTransitioning) {
@@ -160,7 +170,7 @@ class AuthScreens extends React.Component {
if (isLoadingApp) {
App.openApp();
} else {
- App.reconnectApp(this.props.lastUpdateIDAppliedToClient);
+ App.reconnectApp(lastUpdateIDAppliedToClient);
}
});
PusherConnectionManager.init();
@@ -177,33 +187,30 @@ class AuthScreens extends React.Component {
// Note: If a Guide has enabled the memory only key mode then we do want to run OpenApp as their app will not be rehydrated with
// the correct state on refresh. They are explicitly opting out of storing data they would need (i.e. reports_) to take advantage of
// the optimizations performed during ReconnectApp.
- const shouldGetAllData = this.props.isUsingMemoryOnlyKeys || SessionUtils.didUserLogInDuringSession();
if (shouldGetAllData) {
App.openApp();
} else {
- App.reconnectApp(this.props.lastUpdateIDAppliedToClient);
+ App.reconnectApp(lastUpdateIDAppliedToClient);
}
- App.setUpPoliciesAndNavigate(this.props.session, !this.props.isSmallScreenWidth);
+ App.setUpPoliciesAndNavigate(session);
+
App.redirectThirdPartyDesktopSignIn();
// Check if we should be running any demos immediately after signing in.
- if (lodashGet(this.props.demoInfo, 'money2020.isBeginningDemo', false)) {
+ if (lodashGet(demoInfo, 'money2020.isBeginningDemo', false)) {
Navigation.navigate(ROUTES.MONEY2020, CONST.NAVIGATION.TYPE.FORCED_UP);
}
- if (this.props.lastOpenedPublicRoomID) {
+ if (lastOpenedPublicRoomID) {
// Re-open the last opened public room if the user logged in from a public room link
- Report.openLastOpenedPublicRoom(this.props.lastOpenedPublicRoomID);
+ Report.openLastOpenedPublicRoom(lastOpenedPublicRoomID);
}
Download.clearDownloads();
- Timing.end(CONST.TIMING.HOMEPAGE_INITIAL_RENDER);
- const shortcutsOverviewShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SHORTCUTS;
- const searchShortcutConfig = CONST.KEYBOARD_SHORTCUTS.SEARCH;
- const chatShortcutConfig = CONST.KEYBOARD_SHORTCUTS.NEW_CHAT;
+ Timing.end(CONST.TIMING.HOMEPAGE_INITIAL_RENDER);
// Listen to keyboard shortcuts for opening certain pages
- this.unsubscribeShortcutsOverviewShortcut = KeyboardShortcut.subscribe(
+ const unsubscribeShortcutsOverviewShortcut = KeyboardShortcut.subscribe(
shortcutsOverviewShortcutConfig.shortcutKey,
() => {
Modal.close(() => {
@@ -217,168 +224,146 @@ class AuthScreens extends React.Component {
shortcutsOverviewShortcutConfig.modifiers,
true,
);
- this.unsubscribeSearchShortcut = KeyboardShortcut.subscribe(
+
+ // Listen for the key K being pressed so that focus can be given to
+ // the chat switcher, or new group chat
+ // based on the key modifiers pressed and the operating system
+ const unsubscribeSearchShortcut = KeyboardShortcut.subscribe(
searchShortcutConfig.shortcutKey,
() => {
- Modal.close(() => Navigation.navigate(ROUTES.SEARCH));
+ Modal.close(Session.checkIfActionIsAllowed(() => Navigation.navigate(ROUTES.SEARCH)));
},
- searchShortcutConfig.descriptionKey,
- searchShortcutConfig.modifiers,
+ shortcutsOverviewShortcutConfig.descriptionKey,
+ shortcutsOverviewShortcutConfig.modifiers,
true,
);
- this.unsubscribeChatShortcut = KeyboardShortcut.subscribe(
+
+ const unsubscribeChatShortcut = KeyboardShortcut.subscribe(
chatShortcutConfig.shortcutKey,
() => {
- Modal.close(() => Navigation.navigate(ROUTES.NEW));
+ Modal.close(Session.checkIfActionIsAllowed(() => Navigation.navigate(ROUTES.NEW)));
},
chatShortcutConfig.descriptionKey,
chatShortcutConfig.modifiers,
true,
);
- }
- shouldComponentUpdate(nextProps) {
- return nextProps.windowHeight !== this.props.windowHeight || nextProps.isSmallScreenWidth !== this.props.isSmallScreenWidth;
- }
+ return () => {
+ unsubscribeShortcutsOverviewShortcut();
+ unsubscribeSearchShortcut();
+ unsubscribeChatShortcut();
+ Session.cleanupSession();
+ };
- componentWillUnmount() {
- if (this.unsubscribeShortcutsOverviewShortcut) {
- this.unsubscribeShortcutsOverviewShortcut();
- }
- if (this.unsubscribeSearchShortcut) {
- this.unsubscribeSearchShortcut();
- }
- if (this.unsubscribeChatShortcut) {
- this.unsubscribeChatShortcut();
- }
- Session.cleanupSession();
- clearInterval(this.interval);
- this.interval = null;
- }
+ // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, []);
- render() {
- const screenOptions = getRootNavigatorScreenOptions(this.props.isSmallScreenWidth);
-
- return (
-
-
- {
- const SidebarScreen = require('../../../pages/home/sidebar/SidebarScreen').default;
- return SidebarScreen;
- }}
- />
-
- {
- const ValidateLoginPage = require('../../../pages/ValidateLoginPage').default;
- return ValidateLoginPage;
- }}
- />
- {
- const LogOutPreviousUserPage = require('../../../pages/LogOutPreviousUserPage').default;
- return LogOutPreviousUserPage;
- }}
- />
- {
- const ConciergePage = require('../../../pages/ConciergePage').default;
- return ConciergePage;
- }}
- />
-
-
-
- {
- const ReportAttachments = require('../../../pages/home/report/ReportAttachments').default;
- return ReportAttachments;
- }}
- listeners={modalScreenListeners}
- />
-
-
-
-
-
- );
- }
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
}
+AuthScreens.displayName = 'AuthScreens';
AuthScreens.propTypes = propTypes;
AuthScreens.defaultProps = defaultProps;
-export default compose(
- withWindowDimensions,
- withOnyx({
- session: {
- key: ONYXKEYS.SESSION,
- },
- lastOpenedPublicRoomID: {
- key: ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID,
- },
- isUsingMemoryOnlyKeys: {
- key: ONYXKEYS.IS_USING_MEMORY_ONLY_KEYS,
- },
- lastUpdateIDAppliedToClient: {
- key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT,
- },
- demoInfo: {
- key: ONYXKEYS.DEMO_INFO,
- },
- }),
-)(AuthScreens);
+
+const AuthScreensMemoized = memo(AuthScreens, () => true);
+
+export default withOnyx({
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ lastOpenedPublicRoomID: {
+ key: ONYXKEYS.LAST_OPENED_PUBLIC_ROOM_ID,
+ },
+ isUsingMemoryOnlyKeys: {
+ key: ONYXKEYS.IS_USING_MEMORY_ONLY_KEYS,
+ },
+ lastUpdateIDAppliedToClient: {
+ key: ONYXKEYS.ONYX_UPDATES_LAST_UPDATE_ID_APPLIED_TO_CLIENT,
+ },
+ demoInfo: {
+ key: ONYXKEYS.DEMO_INFO,
+ },
+})(AuthScreensMemoized);
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index cfc8f815e4fe..2f0a75a02cc3 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -1,8 +1,8 @@
-import _ from 'underscore';
+import {CardStyleInterpolators, createStackNavigator} from '@react-navigation/stack';
import React from 'react';
-import {createStackNavigator, CardStyleInterpolators} from '@react-navigation/stack';
-import styles from '../../../styles/styles';
-import SCREENS from '../../../SCREENS';
+import _ from 'underscore';
+import styles from '@styles/styles';
+import SCREENS from '@src/SCREENS';
const defaultSubRouteOptions = {
cardStyle: styles.navigationScreenCardStyle,
@@ -18,17 +18,24 @@ const defaultSubRouteOptions = {
*/
function createModalStackNavigator(screens) {
const ModalStackNavigator = createStackNavigator();
- return () => (
-
- {_.map(screens, (getComponent, name) => (
-
- ))}
-
- );
+
+ function ModalStack() {
+ return (
+
+ {_.map(screens, (getComponent, name) => (
+
+ ))}
+
+ );
+ }
+
+ ModalStack.displayName = 'ModalStack';
+
+ return ModalStack;
}
const MoneyRequestModalStackNavigator = createModalStackNavigator({
diff --git a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js
index 64eadcbe06c3..fc75f3544346 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js
+++ b/src/libs/Navigation/AppNavigator/Navigators/CentralPaneNavigator.js
@@ -1,10 +1,10 @@
-import React from 'react';
import {createStackNavigator} from '@react-navigation/stack';
-import SCREENS from '../../../../SCREENS';
-import ReportScreenWrapper from '../ReportScreenWrapper';
-import getCurrentUrl from '../../currentUrl';
-import styles from '../../../../styles/styles';
-import FreezeWrapper from '../../FreezeWrapper';
+import React from 'react';
+import ReportScreenWrapper from '@libs/Navigation/AppNavigator/ReportScreenWrapper';
+import getCurrentUrl from '@libs/Navigation/currentUrl';
+import FreezeWrapper from '@libs/Navigation/FreezeWrapper';
+import styles from '@styles/styles';
+import SCREENS from '@src/SCREENS';
const Stack = createStackNavigator();
diff --git a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js b/src/libs/Navigation/AppNavigator/Navigators/Overlay.js
index 1b2faff8c5e3..a36f98076d22 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/Overlay.js
+++ b/src/libs/Navigation/AppNavigator/Navigators/Overlay.js
@@ -1,13 +1,11 @@
-import React from 'react';
-import {Animated, View} from 'react-native';
import {useCardAnimation} from '@react-navigation/stack';
-
import PropTypes from 'prop-types';
-import styles from '../../../../styles/styles';
-
-import PressableWithoutFeedback from '../../../../components/Pressable/PressableWithoutFeedback';
-import useLocalize from '../../../../hooks/useLocalize';
-import CONST from '../../../../CONST';
+import React from 'react';
+import {Animated, View} from 'react-native';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/* Callback to close the modal */
diff --git a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
index 76203763bb0e..de3fb9e79659 100644
--- a/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
+++ b/src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.js
@@ -1,14 +1,13 @@
-import React from 'react';
-import {View} from 'react-native';
import {createStackNavigator} from '@react-navigation/stack';
import PropTypes from 'prop-types';
-
-import * as ModalStackNavigators from '../ModalStackNavigators';
-import RHPScreenOptions from '../RHPScreenOptions';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
-import styles from '../../../../styles/styles';
+import React from 'react';
+import {View} from 'react-native';
+import NoDropZone from '@components/DragAndDrop/NoDropZone';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as ModalStackNavigators from '@libs/Navigation/AppNavigator/ModalStackNavigators';
+import RHPScreenOptions from '@libs/Navigation/AppNavigator/RHPScreenOptions';
+import styles from '@styles/styles';
import Overlay from './Overlay';
-import NoDropZone from '../../../../components/DragAndDrop/NoDropZone';
const Stack = createStackNavigator();
diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.js b/src/libs/Navigation/AppNavigator/PublicScreens.js
index 7b0afb787278..b50769c7caed 100644
--- a/src/libs/Navigation/AppNavigator/PublicScreens.js
+++ b/src/libs/Navigation/AppNavigator/PublicScreens.js
@@ -1,14 +1,14 @@
-import React from 'react';
import {createStackNavigator} from '@react-navigation/stack';
-import SignInPage from '../../../pages/signin/SignInPage';
-import ValidateLoginPage from '../../../pages/ValidateLoginPage';
-import LogInWithShortLivedAuthTokenPage from '../../../pages/LogInWithShortLivedAuthTokenPage';
-import SCREENS from '../../../SCREENS';
+import React from 'react';
+import LogInWithShortLivedAuthTokenPage from '@pages/LogInWithShortLivedAuthTokenPage';
+import AppleSignInDesktopPage from '@pages/signin/AppleSignInDesktopPage';
+import GoogleSignInDesktopPage from '@pages/signin/GoogleSignInDesktopPage';
+import SAMLSignInPage from '@pages/signin/SAMLSignInPage';
+import SignInPage from '@pages/signin/SignInPage';
+import UnlinkLoginPage from '@pages/UnlinkLoginPage';
+import ValidateLoginPage from '@pages/ValidateLoginPage';
+import SCREENS from '@src/SCREENS';
import defaultScreenOptions from './defaultScreenOptions';
-import UnlinkLoginPage from '../../../pages/UnlinkLoginPage';
-import AppleSignInDesktopPage from '../../../pages/signin/AppleSignInDesktopPage';
-import GoogleSignInDesktopPage from '../../../pages/signin/GoogleSignInDesktopPage';
-import SAMLSignInPage from '../../../pages/signin/SAMLSignInPage';
const RootStack = createStackNavigator();
diff --git a/src/libs/Navigation/AppNavigator/RHPScreenOptions.js b/src/libs/Navigation/AppNavigator/RHPScreenOptions.js
index d7448dcf2314..6adf5bd2b507 100644
--- a/src/libs/Navigation/AppNavigator/RHPScreenOptions.js
+++ b/src/libs/Navigation/AppNavigator/RHPScreenOptions.js
@@ -1,5 +1,5 @@
import {CardStyleInterpolators} from '@react-navigation/stack';
-import styles from '../../../styles/styles';
+import styles from '@styles/styles';
const RHPScreenOptions = {
headerShown: false,
diff --git a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.js b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.js
index 8cfef2439adb..70a33ee34a67 100644
--- a/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.js
+++ b/src/libs/Navigation/AppNavigator/ReportScreenIDSetter.js
@@ -1,13 +1,13 @@
-import {useEffect} from 'react';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import {useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as ReportUtils from '../../ReportUtils';
-import reportPropTypes from '../../../pages/reportPropTypes';
-import * as App from '../../actions/App';
-import usePermissions from '../../../hooks/usePermissions';
-import Navigation from '../Navigation';
+import usePermissions from '@hooks/usePermissions';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import * as App from '@userActions/App';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Available reports that would be displayed in this navigator */
diff --git a/src/libs/Navigation/AppNavigator/ReportScreenWrapper.js b/src/libs/Navigation/AppNavigator/ReportScreenWrapper.js
index 542be8ed859e..87a8a4abc687 100644
--- a/src/libs/Navigation/AppNavigator/ReportScreenWrapper.js
+++ b/src/libs/Navigation/AppNavigator/ReportScreenWrapper.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
-import ReportScreen from '../../../pages/home/ReportScreen';
+import ReportScreen from '@pages/home/ReportScreen';
import ReportScreenIDSetter from './ReportScreenIDSetter';
const propTypes = {
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js
index 42caad5b3969..5d3eb38d49dc 100644
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js
+++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/CustomRouter.js
@@ -1,8 +1,8 @@
-import _ from 'underscore';
import {StackRouter} from '@react-navigation/native';
import lodashFindLast from 'lodash/findLast';
-import NAVIGATORS from '../../../../NAVIGATORS';
-import SCREENS from '../../../../SCREENS';
+import _ from 'underscore';
+import NAVIGATORS from '@src/NAVIGATORS';
+import SCREENS from '@src/SCREENS';
/**
* @param {Object} state - react-navigation state
diff --git a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js
index 58be3d2af3da..ae36f4aff9ad 100644
--- a/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js
+++ b/src/libs/Navigation/AppNavigator/createCustomStackNavigator/index.js
@@ -1,9 +1,9 @@
-import React, {useRef} from 'react';
-import PropTypes from 'prop-types';
-import {useNavigationBuilder, createNavigatorFactory} from '@react-navigation/native';
+import {createNavigatorFactory, useNavigationBuilder} from '@react-navigation/native';
import {StackView} from '@react-navigation/stack';
+import PropTypes from 'prop-types';
+import React, {useRef} from 'react';
+import useWindowDimensions from '@hooks/useWindowDimensions';
import CustomRouter from './CustomRouter';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
const propTypes = {
/* Determines if the navigator should render the StackView (narrow) or ThreePaneView (wide) */
diff --git a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js
index a7456fb071b4..04784fb9d0e1 100644
--- a/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js
+++ b/src/libs/Navigation/AppNavigator/getRootNavigatorScreenOptions.js
@@ -1,8 +1,8 @@
+import getNavigationModalCardStyle from '@styles/getNavigationModalCardStyles';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import CONFIG from '@src/CONFIG';
import modalCardStyleInterpolator from './modalCardStyleInterpolator';
-import styles from '../../../styles/styles';
-import variables from '../../../styles/variables';
-import getNavigationModalCardStyle from '../../../styles/getNavigationModalCardStyles';
-import CONFIG from '../../../CONFIG';
const commonScreenOptions = {
headerShown: false,
diff --git a/src/libs/Navigation/AppNavigator/index.js b/src/libs/Navigation/AppNavigator/index.js
index dee8027b2f30..0d03badf37bc 100644
--- a/src/libs/Navigation/AppNavigator/index.js
+++ b/src/libs/Navigation/AppNavigator/index.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
const propTypes = {
/** If we have an authToken this is true */
diff --git a/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js b/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js
index ec442efbba86..446d195fc466 100644
--- a/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js
+++ b/src/libs/Navigation/AppNavigator/modalCardStyleInterpolator.js
@@ -1,6 +1,6 @@
import {Animated} from 'react-native';
-import variables from '../../../styles/variables';
-import getCardStyles from '../../../styles/cardStyles';
+import getCardStyles from '@styles/cardStyles';
+import variables from '@styles/variables';
export default (isSmallScreenWidth, isFullScreenModal, {current: {progress}, inverted, layouts: {screen}}) => {
const translateX = Animated.multiply(
diff --git a/src/libs/Navigation/FreezeWrapper.js b/src/libs/Navigation/FreezeWrapper.js
index 07b05651a769..592d869dc0de 100644
--- a/src/libs/Navigation/FreezeWrapper.js
+++ b/src/libs/Navigation/FreezeWrapper.js
@@ -1,7 +1,7 @@
-import React, {useEffect, useState, useRef} from 'react';
+import {useIsFocused, useNavigation, useRoute} from '@react-navigation/native';
import lodashFindIndex from 'lodash/findIndex';
import PropTypes from 'prop-types';
-import {useIsFocused, useNavigation, useRoute} from '@react-navigation/native';
+import React, {useEffect, useRef, useState} from 'react';
import {Freeze} from 'react-freeze';
const propTypes = {
diff --git a/src/libs/Navigation/Navigation.js b/src/libs/Navigation/Navigation.js
index 6bbf53ffa6ea..ae13e2b07206 100644
--- a/src/libs/Navigation/Navigation.js
+++ b/src/libs/Navigation/Navigation.js
@@ -1,19 +1,19 @@
+import {getActionFromState} from '@react-navigation/core';
+import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native';
import _ from 'lodash';
import lodashGet from 'lodash/get';
-import {CommonActions, getPathFromState, StackActions} from '@react-navigation/native';
-import {getActionFromState} from '@react-navigation/core';
-import Log from '../Log';
-import linkTo from './linkTo';
-import ROUTES from '../../ROUTES';
-import linkingConfig from './linkingConfig';
-import navigationRef from './navigationRef';
-import NAVIGATORS from '../../NAVIGATORS';
-import originalGetTopmostReportId from './getTopmostReportId';
+import Log from '@libs/Log';
+import CONST from '@src/CONST';
+import NAVIGATORS from '@src/NAVIGATORS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
+import getStateFromPath from './getStateFromPath';
import originalGetTopMostCentralPaneRouteName from './getTopMostCentralPaneRouteName';
import originalGetTopmostReportActionId from './getTopmostReportActionID';
-import getStateFromPath from './getStateFromPath';
-import SCREENS from '../../SCREENS';
-import CONST from '../../CONST';
+import originalGetTopmostReportId from './getTopmostReportId';
+import linkingConfig from './linkingConfig';
+import linkTo from './linkTo';
+import navigationRef from './navigationRef';
let resolveNavigationIsReadyPromise;
const navigationIsReadyPromise = new Promise((resolve) => {
diff --git a/src/libs/Navigation/NavigationRoot.js b/src/libs/Navigation/NavigationRoot.js
index c7a3b14e4fb0..3478f7b8ed8d 100644
--- a/src/libs/Navigation/NavigationRoot.js
+++ b/src/libs/Navigation/NavigationRoot.js
@@ -1,17 +1,17 @@
-import React, {useRef, useEffect, useContext} from 'react';
+import {DefaultTheme, getPathFromState, NavigationContainer} from '@react-navigation/native';
import PropTypes from 'prop-types';
-import {NavigationContainer, DefaultTheme, getPathFromState} from '@react-navigation/native';
-import {useSharedValue, useAnimatedReaction, interpolateColor, withTiming, withDelay, Easing, runOnJS} from 'react-native-reanimated';
-import useFlipper from '../../hooks/useFlipper';
-import Navigation, {navigationRef} from './Navigation';
-import linkingConfig from './linkingConfig';
+import React, {useContext, useEffect, useRef} from 'react';
+import {Easing, interpolateColor, runOnJS, useAnimatedReaction, useSharedValue, withDelay, withTiming} from 'react-native-reanimated';
+import useCurrentReportID from '@hooks/useCurrentReportID';
+import useFlipper from '@hooks/useFlipper';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import Log from '@libs/Log';
+import StatusBar from '@libs/StatusBar';
+import {SidebarNavigationContext} from '@pages/home/sidebar/SidebarNavigationContext';
+import themeColors from '@styles/themes/default';
import AppNavigator from './AppNavigator';
-import themeColors from '../../styles/themes/default';
-import Log from '../Log';
-import StatusBar from '../StatusBar';
-import useCurrentReportID from '../../hooks/useCurrentReportID';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import {SidebarNavigationContext} from '../../pages/home/sidebar/SidebarNavigationContext';
+import linkingConfig from './linkingConfig';
+import Navigation, {navigationRef} from './Navigation';
// https://reactnavigation.org/docs/themes
const navigationTheme = {
diff --git a/src/libs/Navigation/OnyxTabNavigator.js b/src/libs/Navigation/OnyxTabNavigator.js
index 158160e9aa13..eeed3e0cd270 100644
--- a/src/libs/Navigation/OnyxTabNavigator.js
+++ b/src/libs/Navigation/OnyxTabNavigator.js
@@ -1,9 +1,9 @@
-import React from 'react';
import {createMaterialTopTabNavigator} from '@react-navigation/material-top-tabs';
-import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
-import Tab from '../actions/Tab';
-import ONYXKEYS from '../../ONYXKEYS';
+import React from 'react';
+import {withOnyx} from 'react-native-onyx';
+import Tab from '@userActions/Tab';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** ID of the tab component to be saved in onyx */
diff --git a/src/libs/Navigation/linkTo.js b/src/libs/Navigation/linkTo.js
index fcb3bd5df9c5..e77d787ab4f8 100644
--- a/src/libs/Navigation/linkTo.js
+++ b/src/libs/Navigation/linkTo.js
@@ -1,11 +1,11 @@
import {getActionFromState} from '@react-navigation/core';
import _ from 'lodash';
-import NAVIGATORS from '../../NAVIGATORS';
-import linkingConfig from './linkingConfig';
-import getTopmostReportId from './getTopmostReportId';
+import CONST from '@src/CONST';
+import NAVIGATORS from '@src/NAVIGATORS';
import getStateFromPath from './getStateFromPath';
-import CONST from '../../CONST';
import getTopMostCentralPaneRouteName from './getTopMostCentralPaneRouteName';
+import getTopmostReportId from './getTopmostReportId';
+import linkingConfig from './linkingConfig';
/**
* Motivation for this function is described in NAVIGATION.md
diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js
index 79609f551ee4..fff86b684872 100644
--- a/src/libs/Navigation/linkingConfig.js
+++ b/src/libs/Navigation/linkingConfig.js
@@ -1,7 +1,7 @@
-import ROUTES from '../../ROUTES';
-import SCREENS from '../../SCREENS';
-import CONST from '../../CONST';
-import NAVIGATORS from '../../NAVIGATORS';
+import CONST from '@src/CONST';
+import NAVIGATORS from '@src/NAVIGATORS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
export default {
prefixes: ['new-expensify://', 'https://www.expensify.cash', 'https://staging.expensify.cash', 'http://localhost', CONST.NEW_EXPENSIFY_URL, CONST.STAGING_NEW_EXPENSIFY_URL],
diff --git a/src/libs/Navigation/shouldPreventDeeplinkPrompt/index.js b/src/libs/Navigation/shouldPreventDeeplinkPrompt/index.js
index 861e40eaa24d..23f46cb9808f 100644
--- a/src/libs/Navigation/shouldPreventDeeplinkPrompt/index.js
+++ b/src/libs/Navigation/shouldPreventDeeplinkPrompt/index.js
@@ -1,4 +1,4 @@
-import CONST from '../../../CONST';
+import CONST from '@src/CONST';
/**
* Determines if the deeplink prompt should be shown on the current screen
diff --git a/src/libs/Network/MainQueue.ts b/src/libs/Network/MainQueue.ts
index 5f069e2d0ed4..3ae0d44680a4 100644
--- a/src/libs/Network/MainQueue.ts
+++ b/src/libs/Network/MainQueue.ts
@@ -1,7 +1,7 @@
+import * as Request from '@libs/Request';
+import OnyxRequest from '@src/types/onyx/Request';
import * as NetworkStore from './NetworkStore';
import * as SequentialQueue from './SequentialQueue';
-import * as Request from '../Request';
-import OnyxRequest from '../../types/onyx/Request';
// Queue for network requests so we don't lose actions done by the user while offline
let networkRequestQueue: OnyxRequest[] = [];
diff --git a/src/libs/Network/NetworkStore.ts b/src/libs/Network/NetworkStore.ts
index 0910031bdb63..52e4147f1b3c 100644
--- a/src/libs/Network/NetworkStore.ts
+++ b/src/libs/Network/NetworkStore.ts
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import Credentials from '../../types/onyx/Credentials';
+import ONYXKEYS from '@src/ONYXKEYS';
+import Credentials from '@src/types/onyx/Credentials';
let credentials: Credentials | null = null;
let authToken: string | null = null;
diff --git a/src/libs/Network/SequentialQueue.ts b/src/libs/Network/SequentialQueue.ts
index 980bbc0efc44..d4aee4a221e5 100644
--- a/src/libs/Network/SequentialQueue.ts
+++ b/src/libs/Network/SequentialQueue.ts
@@ -1,13 +1,13 @@
import Onyx from 'react-native-onyx';
-import * as PersistedRequests from '../actions/PersistedRequests';
+import * as ActiveClientManager from '@libs/ActiveClientManager';
+import * as Request from '@libs/Request';
+import * as RequestThrottle from '@libs/RequestThrottle';
+import * as PersistedRequests from '@userActions/PersistedRequests';
+import * as QueuedOnyxUpdates from '@userActions/QueuedOnyxUpdates';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import OnyxRequest from '@src/types/onyx/Request';
import * as NetworkStore from './NetworkStore';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as ActiveClientManager from '../ActiveClientManager';
-import * as Request from '../Request';
-import * as RequestThrottle from '../RequestThrottle';
-import CONST from '../../CONST';
-import * as QueuedOnyxUpdates from '../actions/QueuedOnyxUpdates';
-import OnyxRequest from '../../types/onyx/Request';
let resolveIsReadyPromise: ((args?: unknown[]) => void) | undefined;
let isReadyPromise = new Promise((resolve) => {
diff --git a/src/libs/Network/enhanceParameters.ts b/src/libs/Network/enhanceParameters.ts
index 54d72a7c6c99..6ff54f94bc88 100644
--- a/src/libs/Network/enhanceParameters.ts
+++ b/src/libs/Network/enhanceParameters.ts
@@ -1,5 +1,5 @@
-import CONFIG from '../../CONFIG';
-import getPlatform from '../getPlatform';
+import getPlatform from '@libs/getPlatform';
+import CONFIG from '@src/CONFIG';
import * as NetworkStore from './NetworkStore';
/**
diff --git a/src/libs/Network/index.ts b/src/libs/Network/index.ts
index bf38bc33e95a..4ccb8df01163 100644
--- a/src/libs/Network/index.ts
+++ b/src/libs/Network/index.ts
@@ -1,10 +1,10 @@
-import * as ActiveClientManager from '../ActiveClientManager';
-import CONST from '../../CONST';
+import * as ActiveClientManager from '@libs/ActiveClientManager';
+import CONST from '@src/CONST';
+import {Request} from '@src/types/onyx';
+import Response from '@src/types/onyx/Response';
+import pkg from '../../../package.json';
import * as MainQueue from './MainQueue';
import * as SequentialQueue from './SequentialQueue';
-import pkg from '../../../package.json';
-import {Request} from '../../types/onyx';
-import Response from '../../types/onyx/Response';
// We must wait until the ActiveClientManager is ready so that we ensure only the "leader" tab processes any persisted requests
ActiveClientManager.isReady().then(() => {
diff --git a/src/libs/NetworkConnection.ts b/src/libs/NetworkConnection.ts
index 663a9c1b37d5..e150b8b650c1 100644
--- a/src/libs/NetworkConnection.ts
+++ b/src/libs/NetworkConnection.ts
@@ -1,12 +1,12 @@
-import Onyx from 'react-native-onyx';
import NetInfo from '@react-native-community/netinfo';
import throttle from 'lodash/throttle';
+import Onyx from 'react-native-onyx';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import * as NetworkActions from './actions/Network';
import AppStateMonitor from './AppStateMonitor';
import Log from './Log';
-import * as NetworkActions from './actions/Network';
-import CONFIG from '../CONFIG';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
let isOffline = false;
let hasPendingNetworkCheck = false;
diff --git a/src/libs/NextStepUtils.js b/src/libs/NextStepUtils.js
index 78214bac7df9..303f9b2a9925 100644
--- a/src/libs/NextStepUtils.js
+++ b/src/libs/NextStepUtils.js
@@ -1,5 +1,5 @@
-import _ from 'underscore';
import Str from 'expensify-common/lib/str';
+import _ from 'underscore';
function parseMessage(messageToParse) {
let nextStepHTML = '';
diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js
index 3199e4c6388d..20d9be48d915 100644
--- a/src/libs/Notification/LocalNotification/BrowserNotifications.js
+++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js
@@ -1,9 +1,9 @@
// Web and desktop implementation only. Do not import for direct use. Use LocalNotification.
import _ from 'underscore';
+import EXPENSIFY_ICON_URL from '@assets/images/expensify-logo-round-clearspace.png';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as AppUpdate from '@userActions/AppUpdate';
import focusApp from './focusApp';
-import * as AppUpdate from '../../actions/AppUpdate';
-import EXPENSIFY_ICON_URL from '../../../../assets/images/expensify-logo-round-clearspace.png';
-import * as ReportUtils from '../../ReportUtils';
const DEFAULT_DELAY = 4000;
diff --git a/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js
index 0afc8fe10490..b36c0d0c7d18 100644
--- a/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js
+++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.android.js
@@ -1,5 +1,5 @@
import Airship from '@ua/react-native-airship';
-import shouldShowPushNotification from '../shouldShowPushNotification';
+import shouldShowPushNotification from '@libs/Notification/PushNotification/shouldShowPushNotification';
function configureForegroundNotifications() {
Airship.push.android.setForegroundDisplayPredicate((pushPayload) => Promise.resolve(shouldShowPushNotification(pushPayload)));
diff --git a/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js
index 17ad1baaebe3..0f0929951a90 100644
--- a/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js
+++ b/src/libs/Notification/PushNotification/ForegroundNotifications/index.ios.js
@@ -1,5 +1,5 @@
import Airship, {iOS} from '@ua/react-native-airship';
-import shouldShowPushNotification from '../shouldShowPushNotification';
+import shouldShowPushNotification from '@libs/Notification/PushNotification/shouldShowPushNotification';
function configureForegroundNotifications() {
// Set our default iOS foreground presentation to be loud with a banner
diff --git a/src/libs/Notification/PushNotification/backgroundRefresh/index.android.js b/src/libs/Notification/PushNotification/backgroundRefresh/index.android.js
index d86589e2f207..b672069727a5 100644
--- a/src/libs/Notification/PushNotification/backgroundRefresh/index.android.js
+++ b/src/libs/Notification/PushNotification/backgroundRefresh/index.android.js
@@ -1,7 +1,7 @@
import Onyx from 'react-native-onyx';
-import * as App from '../../../actions/App';
-import Visibility from '../../../Visibility';
-import ONYXKEYS from '../../../../ONYXKEYS';
+import Visibility from '@libs/Visibility';
+import * as App from '@userActions/App';
+import ONYXKEYS from '@src/ONYXKEYS';
function getLastOnyxUpdateID() {
return new Promise((resolve) => {
diff --git a/src/libs/Notification/PushNotification/index.native.js b/src/libs/Notification/PushNotification/index.native.js
index 7192ee66a791..8513a88e46d3 100644
--- a/src/libs/Notification/PushNotification/index.native.js
+++ b/src/libs/Notification/PushNotification/index.native.js
@@ -1,12 +1,12 @@
-import _ from 'underscore';
-import Onyx from 'react-native-onyx';
import Airship, {EventType} from '@ua/react-native-airship';
import lodashGet from 'lodash/get';
-import Log from '../../Log';
-import NotificationType from './NotificationType';
-import * as PushNotification from '../../actions/PushNotification';
-import ONYXKEYS from '../../../ONYXKEYS';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import Log from '@libs/Log';
+import * as PushNotification from '@userActions/PushNotification';
+import ONYXKEYS from '@src/ONYXKEYS';
import ForegroundNotifications from './ForegroundNotifications';
+import NotificationType from './NotificationType';
let isUserOptedInToPushNotifications = false;
Onyx.connect({
diff --git a/src/libs/Notification/PushNotification/shouldShowPushNotification.js b/src/libs/Notification/PushNotification/shouldShowPushNotification.js
index b9b9d974374c..f25d452a77d5 100644
--- a/src/libs/Notification/PushNotification/shouldShowPushNotification.js
+++ b/src/libs/Notification/PushNotification/shouldShowPushNotification.js
@@ -1,7 +1,7 @@
import _ from 'underscore';
-import * as Report from '../../actions/Report';
-import Log from '../../Log';
-import * as ReportActionUtils from '../../ReportActionsUtils';
+import Log from '@libs/Log';
+import * as ReportActionUtils from '@libs/ReportActionsUtils';
+import * as Report from '@userActions/Report';
/**
* Returns whether the given Airship notification should be shown depending on the current state of the app
diff --git a/src/libs/Notification/PushNotification/subscribePushNotification/index.js b/src/libs/Notification/PushNotification/subscribePushNotification/index.js
index 45dc8d8a7ae9..c5519b42dc09 100644
--- a/src/libs/Notification/PushNotification/subscribePushNotification/index.js
+++ b/src/libs/Notification/PushNotification/subscribePushNotification/index.js
@@ -1,7 +1,7 @@
import Onyx from 'react-native-onyx';
+import subscribeToReportCommentPushNotifications from '@libs/Notification/PushNotification/subscribeToReportCommentPushNotifications';
+import ONYXKEYS from '@src/ONYXKEYS';
import PushNotification from '..';
-import subscribeToReportCommentPushNotifications from '../subscribeToReportCommentPushNotifications';
-import ONYXKEYS from '../../../../ONYXKEYS';
/**
* Manage push notification subscriptions on sign-in/sign-out.
diff --git a/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js b/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js
index aadc7d6c3983..04fd34bf6075 100644
--- a/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js
+++ b/src/libs/Notification/PushNotification/subscribeToReportCommentPushNotifications.js
@@ -1,10 +1,10 @@
import Onyx from 'react-native-onyx';
-import PushNotification from '.';
-import ROUTES from '../../../ROUTES';
-import Log from '../../Log';
-import Navigation from '../../Navigation/Navigation';
-import Visibility from '../../Visibility';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import Visibility from '@libs/Visibility';
+import ROUTES from '@src/ROUTES';
import backgroundRefresh from './backgroundRefresh';
+import PushNotification from './index';
/**
* Setup reportComment push notification callbacks.
diff --git a/src/libs/NumberUtils.ts b/src/libs/NumberUtils.ts
index 6e8d0fa4362b..ddbd42243758 100644
--- a/src/libs/NumberUtils.ts
+++ b/src/libs/NumberUtils.ts
@@ -1,4 +1,4 @@
-import CONST from '../CONST';
+import CONST from '@src/CONST';
/**
* Generates a random positive 64 bit numeric string by randomly generating the left, middle, and right parts and concatenating them. Used to generate client-side ids.
diff --git a/src/libs/OnyxSelectors/reportWithoutHasDraftSelector.ts b/src/libs/OnyxSelectors/reportWithoutHasDraftSelector.ts
index 8819cc8aa47c..9fd89cfdf146 100644
--- a/src/libs/OnyxSelectors/reportWithoutHasDraftSelector.ts
+++ b/src/libs/OnyxSelectors/reportWithoutHasDraftSelector.ts
@@ -1,4 +1,4 @@
-import {OnyxKeyValue} from '../../ONYXKEYS';
+import {OnyxKeyValue} from '@src/ONYXKEYS';
export default function reportWithoutHasDraftSelector(report: OnyxKeyValue<'report_'>) {
if (!report) {
diff --git a/src/libs/OptionsListUtils.js b/src/libs/OptionsListUtils.js
index e909f0d86453..74382c8b9065 100644
--- a/src/libs/OptionsListUtils.js
+++ b/src/libs/OptionsListUtils.js
@@ -1,24 +1,25 @@
/* eslint-disable no-continue */
-import _ from 'underscore';
-import Onyx from 'react-native-onyx';
-import lodashOrderBy from 'lodash/orderBy';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
import {parsePhoneNumber} from 'awesome-phonenumber';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
-import * as ReportUtils from './ReportUtils';
-import * as Localize from './Localize';
-import Permissions from './Permissions';
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
+import lodashOrderBy from 'lodash/orderBy';
+import lodashSet from 'lodash/set';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as CollectionUtils from './CollectionUtils';
-import Navigation from './Navigation/Navigation';
-import * as LoginUtils from './LoginUtils';
+import * as ErrorUtils from './ErrorUtils';
import * as LocalePhoneNumber from './LocalePhoneNumber';
-import * as UserUtils from './UserUtils';
-import * as ReportActionUtils from './ReportActionsUtils';
+import * as Localize from './Localize';
+import * as LoginUtils from './LoginUtils';
+import Navigation from './Navigation/Navigation';
+import Permissions from './Permissions';
import * as PersonalDetailsUtils from './PersonalDetailsUtils';
-import * as ErrorUtils from './ErrorUtils';
+import * as ReportActionUtils from './ReportActionsUtils';
+import * as ReportUtils from './ReportUtils';
import * as TransactionUtils from './TransactionUtils';
+import * as UserUtils from './UserUtils';
/**
* OptionsListUtils is used to build a list options passed to the OptionsList component. Several different UI views can
@@ -664,7 +665,87 @@ function hasEnabledOptions(options) {
}
/**
- * Build the options for the category tree hierarchy via indents
+ * Sorts categories using a simple object.
+ * It builds an hierarchy (based on an object), where each category has a name and other keys as subcategories.
+ * Via the hierarchy we avoid duplicating and sort categories one by one. Subcategories are being sorted alphabetically.
+ *
+ * @param {Object} categories
+ * @returns {Array}
+ */
+function sortCategories(categories) {
+ // Sorts categories alphabetically by name.
+ const sortedCategories = _.chain(categories)
+ .values()
+ .sortBy((category) => category.name)
+ .value();
+
+ // An object that respects nesting of categories. Also, can contain only uniq categories.
+ const hierarchy = {};
+
+ /**
+ * Iterates over all categories to set each category in a proper place in hierarchy
+ * It gets a path based on a category name e.g. "Parent: Child: Subcategory" -> "Parent.Child.Subcategory".
+ * {
+ * Parent: {
+ * name: "Parent",
+ * Child: {
+ * name: "Child"
+ * Subcategory: {
+ * name: "Subcategory"
+ * }
+ * }
+ * }
+ * }
+ */
+ _.each(sortedCategories, (category) => {
+ const path = category.name.split(CONST.PARENT_CHILD_SEPARATOR);
+ const existedValue = lodashGet(hierarchy, path, {});
+
+ lodashSet(hierarchy, path, {
+ ...existedValue,
+ name: category.name,
+ });
+ });
+
+ /**
+ * A recursive function to convert hierarchy into an array of category objects.
+ * The category object contains base 2 properties: "name" and "enabled".
+ * It iterates each key one by one. When a category has subcategories, goes deeper into them. Also, sorts subcategories alphabetically.
+ *
+ * @param {Object} initialHierarchy
+ * @returns {Array}
+ */
+ const flatHierarchy = (initialHierarchy) =>
+ _.reduce(
+ initialHierarchy,
+ (acc, category) => {
+ const {name, ...subcategories} = category;
+
+ if (!_.isEmpty(name)) {
+ const categoryObject = {
+ name,
+ enabled: lodashGet(categories, [name, 'enabled'], false),
+ };
+
+ acc.push(categoryObject);
+ }
+
+ if (!_.isEmpty(subcategories)) {
+ const nestedCategories = flatHierarchy(subcategories);
+
+ acc.push(..._.sortBy(nestedCategories, 'name'));
+ }
+
+ return acc;
+ },
+ [],
+ );
+
+ return flatHierarchy(hierarchy);
+}
+
+/**
+ * Builds the options for the category tree hierarchy via indents
*
* @param {Object[]} options - an initial object array
* @param {Boolean} options[].enabled - a flag to enable/disable option in a list
@@ -673,25 +754,21 @@ function hasEnabledOptions(options) {
* @returns {Array}
*/
function getCategoryOptionTree(options, isOneLine = false) {
- const optionCollection = {};
+ const optionCollection = new Map();
_.each(options, (option) => {
- if (!option.enabled) {
- return;
- }
-
if (isOneLine) {
- if (_.has(optionCollection, option.name)) {
+ if (optionCollection.has(option.name)) {
return;
}
- optionCollection[option.name] = {
+ optionCollection.set(option.name, {
text: option.name,
keyForList: option.name,
searchText: option.name,
tooltipText: option.name,
isDisabled: !option.enabled,
- };
+ });
return;
}
@@ -699,26 +776,27 @@ function getCategoryOptionTree(options, isOneLine = false) {
option.name.split(CONST.PARENT_CHILD_SEPARATOR).forEach((optionName, index, array) => {
const indents = _.times(index, () => CONST.INDENTS).join('');
const isChild = array.length - 1 === index;
+ const searchText = array.slice(0, index + 1).join(CONST.PARENT_CHILD_SEPARATOR);
- if (_.has(optionCollection, optionName)) {
+ if (optionCollection.has(searchText)) {
return;
}
- optionCollection[optionName] = {
+ optionCollection.set(searchText, {
text: `${indents}${optionName}`,
- keyForList: optionName,
- searchText: array.slice(0, index + 1).join(CONST.PARENT_CHILD_SEPARATOR),
+ keyForList: searchText,
+ searchText,
tooltipText: optionName,
isDisabled: isChild ? !option.enabled : true,
- };
+ });
});
});
- return _.values(optionCollection);
+ return Array.from(optionCollection.values());
}
/**
- * Build the section list for categories
+ * Builds the section list for categories
*
* @param {Object} categories
* @param {String[]} recentlyUsedCategories
@@ -729,13 +807,12 @@ function getCategoryOptionTree(options, isOneLine = false) {
* @returns {Array}
*/
function getCategoryListSections(categories, recentlyUsedCategories, selectedOptions, searchInputValue, maxRecentReportsToShow) {
+ const sortedCategories = sortCategories(categories);
+ const enabledCategories = _.filter(sortedCategories, (category) => category.enabled);
+
const categorySections = [];
- const categoriesValues = _.chain(categories)
- .values()
- .filter((category) => category.enabled)
- .value();
+ const numberOfCategories = _.size(enabledCategories);
- const numberOfCategories = _.size(categoriesValues);
let indexOffset = 0;
if (numberOfCategories === 0 && selectedOptions.length > 0) {
@@ -751,7 +828,7 @@ function getCategoryListSections(categories, recentlyUsedCategories, selectedOpt
}
if (!_.isEmpty(searchInputValue)) {
- const searchCategories = _.filter(categoriesValues, (category) => category.name.toLowerCase().includes(searchInputValue.toLowerCase()));
+ const searchCategories = _.filter(enabledCategories, (category) => category.name.toLowerCase().includes(searchInputValue.toLowerCase()));
categorySections.push({
// "Search" section
@@ -770,22 +847,12 @@ function getCategoryListSections(categories, recentlyUsedCategories, selectedOpt
title: '',
shouldShow: false,
indexOffset,
- data: getCategoryOptionTree(categoriesValues),
+ data: getCategoryOptionTree(enabledCategories),
});
return categorySections;
}
- const selectedOptionNames = _.map(selectedOptions, (selectedOption) => selectedOption.name);
- const filteredRecentlyUsedCategories = _.map(
- _.filter(recentlyUsedCategories, (category) => !_.includes(selectedOptionNames, category)),
- (category) => ({
- name: category,
- enabled: lodashGet(categories, `${category}.enabled`, false),
- }),
- );
- const filteredCategories = _.filter(categoriesValues, (category) => !_.includes(selectedOptionNames, category.name));
-
if (!_.isEmpty(selectedOptions)) {
categorySections.push({
// "Selected" section
@@ -798,6 +865,15 @@ function getCategoryListSections(categories, recentlyUsedCategories, selectedOpt
indexOffset += selectedOptions.length;
}
+ const selectedOptionNames = _.map(selectedOptions, (selectedOption) => selectedOption.name);
+ const filteredRecentlyUsedCategories = _.chain(recentlyUsedCategories)
+ .filter((categoryName) => !_.includes(selectedOptionNames, categoryName) && lodashGet(categories, [categoryName, 'enabled'], false))
+ .map((categoryName) => ({
+ name: categoryName,
+ enabled: lodashGet(categories, [categoryName, 'enabled'], false),
+ }))
+ .value();
+
if (!_.isEmpty(filteredRecentlyUsedCategories)) {
const cutRecentlyUsedCategories = filteredRecentlyUsedCategories.slice(0, maxRecentReportsToShow);
@@ -812,6 +888,8 @@ function getCategoryListSections(categories, recentlyUsedCategories, selectedOpt
indexOffset += filteredRecentlyUsedCategories.length;
}
+ const filteredCategories = _.filter(enabledCategories, (category) => !_.includes(selectedOptionNames, category.name));
+
categorySections.push({
// "All" section when items amount more than the threshold
title: Localize.translateLocal('common.all'),
@@ -1668,6 +1746,7 @@ export {
getLastMessageTextForReport,
getEnabledCategoriesCount,
hasEnabledOptions,
+ sortCategories,
getCategoryOptionTree,
formatMemberForList,
formatSectionsFromSearchTerm,
diff --git a/src/libs/PaymentUtils.ts b/src/libs/PaymentUtils.ts
index 380f10589b3f..b37db2584394 100644
--- a/src/libs/PaymentUtils.ts
+++ b/src/libs/PaymentUtils.ts
@@ -1,10 +1,10 @@
-import BankAccountModel from './models/BankAccount';
-import getBankIcon from '../components/Icon/BankIcons';
-import CONST from '../CONST';
+import getBankIcon from '@components/Icon/BankIcons';
+import CONST from '@src/CONST';
+import BankAccount from '@src/types/onyx/BankAccount';
+import Fund from '@src/types/onyx/Fund';
+import PaymentMethod from '@src/types/onyx/PaymentMethod';
import * as Localize from './Localize';
-import Fund from '../types/onyx/Fund';
-import BankAccount from '../types/onyx/BankAccount';
-import PaymentMethod from '../types/onyx/PaymentMethod';
+import BankAccountModel from './models/BankAccount';
type AccountType = BankAccount['accountType'] | Fund['accountType'];
diff --git a/src/libs/Performance.tsx b/src/libs/Performance.tsx
index cfb5e258c9f8..45ae0f5cc5f0 100644
--- a/src/libs/Performance.tsx
+++ b/src/libs/Performance.tsx
@@ -1,15 +1,14 @@
-import React, {Profiler, forwardRef} from 'react';
-import {Alert, InteractionManager} from 'react-native';
-import lodashTransform from 'lodash/transform';
-import isObject from 'lodash/isObject';
import isEqual from 'lodash/isEqual';
-import {Performance as RNPerformance, PerformanceEntry, PerformanceMark, PerformanceMeasure} from 'react-native-performance';
+import isObject from 'lodash/isObject';
+import lodashTransform from 'lodash/transform';
+import React, {forwardRef, Profiler} from 'react';
+import {Alert, InteractionManager} from 'react-native';
+import {PerformanceEntry, PerformanceMark, PerformanceMeasure, Performance as RNPerformance} from 'react-native-performance';
import {PerformanceObserverEntryList} from 'react-native-performance/lib/typescript/performance-observer';
-
-import * as Metrics from './Metrics';
-import getComponentDisplayName from './getComponentDisplayName';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
import isE2ETestSession from './E2E/isE2ETestSession';
+import getComponentDisplayName from './getComponentDisplayName';
+import * as Metrics from './Metrics';
type WrappedComponentConfig = {id: string};
diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts
index 13489c396c3c..2eb1d3b02f25 100644
--- a/src/libs/Permissions.ts
+++ b/src/libs/Permissions.ts
@@ -1,5 +1,5 @@
-import CONST from '../CONST';
-import Beta from '../types/onyx/Beta';
+import CONST from '@src/CONST';
+import Beta from '@src/types/onyx/Beta';
function canUseAllBetas(betas: Beta[]): boolean {
return betas?.includes(CONST.BETAS.ALL);
@@ -42,10 +42,6 @@ function canUseCustomStatus(betas: Beta[]): boolean {
return betas?.includes(CONST.BETAS.CUSTOM_STATUS) || canUseAllBetas(betas);
}
-function canUseCategories(betas: Beta[]): boolean {
- return betas?.includes(CONST.BETAS.NEW_DOT_CATEGORIES) || canUseAllBetas(betas);
-}
-
function canUseTags(betas: Beta[]): boolean {
return betas?.includes(CONST.BETAS.NEW_DOT_TAGS) || canUseAllBetas(betas);
}
@@ -66,7 +62,6 @@ export default {
canUsePolicyRooms,
canUseTasks,
canUseCustomStatus,
- canUseCategories,
canUseTags,
canUseLinkPreviews,
};
diff --git a/src/libs/PersonalDetailsUtils.js b/src/libs/PersonalDetailsUtils.js
index 29c49427bc81..e346dcde4fc4 100644
--- a/src/libs/PersonalDetailsUtils.js
+++ b/src/libs/PersonalDetailsUtils.js
@@ -1,10 +1,10 @@
import lodashGet from 'lodash/get';
import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import ONYXKEYS from '../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
+import * as LocalePhoneNumber from './LocalePhoneNumber';
import * as Localize from './Localize';
import * as UserUtils from './UserUtils';
-import * as LocalePhoneNumber from './LocalePhoneNumber';
let personalDetails = [];
let allPersonalDetails = {};
@@ -17,8 +17,8 @@ Onyx.connect({
});
/**
- * @param {Object} passedPersonalDetails
- * @param {Array} pathToDisplayName
+ * @param {Object | Null} passedPersonalDetails
+ * @param {Array | String} pathToDisplayName
* @param {String} [defaultValue] optional default display name value
* @returns {String}
*/
diff --git a/src/libs/PolicyUtils.js b/src/libs/PolicyUtils.js
deleted file mode 100644
index 2ecc818ebd23..000000000000
--- a/src/libs/PolicyUtils.js
+++ /dev/null
@@ -1,292 +0,0 @@
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-
-/**
- * Filter out the active policies, which will exclude policies with pending deletion
- * These are policies that we can use to create reports with in NewDot.
- * @param {Object} policies
- * @returns {Array}
- */
-function getActivePolicies(policies) {
- return _.filter(policies, (policy) => policy && (policy.isPolicyExpenseChatEnabled || policy.areChatRoomsEnabled) && policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE);
-}
-
-/**
- * Checks if we have any errors stored within the POLICY_MEMBERS. Determines whether we should show a red brick road error or not.
- * Data structure: {accountID: {role:'user', errors: []}, accountID2: {role:'admin', errors: [{1231312313: 'Unable to do X'}]}, ...}
- *
- * @param {Object} policyMembers
- * @returns {Boolean}
- */
-function hasPolicyMemberError(policyMembers) {
- return _.some(policyMembers, (member) => !_.isEmpty(member.errors));
-}
-
-/**
- * Check if the policy has any error fields.
- *
- * @param {Object} policy
- * @param {Object} policy.errorFields
- * @return {Boolean}
- */
-function hasPolicyErrorFields(policy) {
- return _.some(lodashGet(policy, 'errorFields', {}), (fieldErrors) => !_.isEmpty(fieldErrors));
-}
-
-/**
- * Check if the policy has any errors, and if it doesn't, then check if it has any error fields.
- *
- * @param {Object} policy
- * @param {Object} policy.errors
- * @param {Object} policy.errorFields
- * @return {Boolean}
- */
-function hasPolicyError(policy) {
- return !_.isEmpty(lodashGet(policy, 'errors', {})) ? true : hasPolicyErrorFields(policy);
-}
-
-/**
- * Checks if we have any errors stored within the policy custom units.
- *
- * @param {Object} policy
- * @returns {Boolean}
- */
-function hasCustomUnitsError(policy) {
- return !_.isEmpty(_.pick(lodashGet(policy, 'customUnits', {}), 'errors'));
-}
-
-/**
- * @param {Number} value
- * @param {Function} toLocaleDigit
- * @returns {Number}
- */
-function getNumericValue(value, toLocaleDigit) {
- const numValue = parseFloat(value.toString().replace(toLocaleDigit('.'), '.'));
- if (Number.isNaN(numValue)) {
- return NaN;
- }
- return numValue.toFixed(CONST.CUSTOM_UNITS.RATE_DECIMALS);
-}
-
-/**
- * @param {Number} value
- * @param {Function} toLocaleDigit
- * @returns {String}
- */
-function getRateDisplayValue(value, toLocaleDigit) {
- const numValue = getNumericValue(value, toLocaleDigit);
- if (Number.isNaN(numValue)) {
- return '';
- }
- return numValue.toString().replace('.', toLocaleDigit('.')).substring(0, value.length);
-}
-
-/**
- * @param {Object} customUnitRate
- * @param {Number} customUnitRate.rate
- * @param {Function} toLocaleDigit
- * @returns {String}
- */
-function getUnitRateValue(customUnitRate, toLocaleDigit) {
- return getRateDisplayValue(lodashGet(customUnitRate, 'rate', 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET, toLocaleDigit);
-}
-
-/**
- * Get the brick road indicator status for a policy. The policy has an error status if there is a policy member error, a custom unit error or a field error.
- *
- * @param {Object} policy
- * @param {String} policy.id
- * @param {Object} policyMembersCollection
- * @returns {String}
- */
-function getPolicyBrickRoadIndicatorStatus(policy, policyMembersCollection) {
- const policyMembers = lodashGet(policyMembersCollection, `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policy.id}`, {});
- if (hasPolicyMemberError(policyMembers) || hasCustomUnitsError(policy) || hasPolicyErrorFields(policy)) {
- return CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
- }
- return '';
-}
-
-/**
- * Check if the policy can be displayed
- * If offline, always show the policy pending deletion.
- * If online, show the policy pending deletion only if there is an error.
- * Note: Using a local ONYXKEYS.NETWORK subscription will cause a delay in
- * updating the screen. Passing the offline status from the component.
- * @param {Object} policy
- * @param {Boolean} isOffline
- * @returns {Boolean}
- */
-function shouldShowPolicy(policy, isOffline) {
- return (
- policy &&
- policy.isPolicyExpenseChatEnabled &&
- policy.role === CONST.POLICY.ROLE.ADMIN &&
- (isOffline || policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(policy.errors))
- );
-}
-
-/**
- * @param {string} email
- * @returns {boolean}
- */
-function isExpensifyTeam(email) {
- const emailDomain = Str.extractEmailDomain(email);
- return emailDomain === CONST.EXPENSIFY_PARTNER_NAME || emailDomain === CONST.EMAIL.GUIDES_DOMAIN;
-}
-
-/**
- * @param {string} email
- * @returns {boolean}
- */
-function isExpensifyGuideTeam(email) {
- const emailDomain = Str.extractEmailDomain(email);
- return emailDomain === CONST.EMAIL.GUIDES_DOMAIN;
-}
-
-/**
- * Checks if the current user is an admin of the policy.
- *
- * @param {Object} policy
- * @returns {Boolean}
- */
-const isPolicyAdmin = (policy) => lodashGet(policy, 'role') === CONST.POLICY.ROLE.ADMIN;
-
-/**
- *
- * @param {String} policyID
- * @param {Object} policies
- * @returns {Boolean}
- */
-const isPolicyMember = (policyID, policies) => _.some(policies, (policy) => lodashGet(policy, 'id') === policyID);
-
-/**
- * @param {Object} policyMembers
- * @param {Object} personalDetails
- * @returns {Object}
- *
- * Create an object mapping member emails to their accountIDs. Filter for members without errors, and get the login email from the personalDetail object using the accountID.
- *
- * We only return members without errors. Otherwise, the members with errors would immediately be removed before the user has a chance to read the error.
- */
-function getMemberAccountIDsForWorkspace(policyMembers, personalDetails) {
- const memberEmailsToAccountIDs = {};
- _.each(policyMembers, (member, accountID) => {
- if (!_.isEmpty(member.errors)) {
- return;
- }
- const personalDetail = personalDetails[accountID];
- if (!personalDetail || !personalDetail.login) {
- return;
- }
- memberEmailsToAccountIDs[personalDetail.login] = Number(accountID);
- });
- return memberEmailsToAccountIDs;
-}
-
-/**
- * Get login list that we should not show in the workspace invite options
- *
- * @param {Object} policyMembers
- * @param {Object} personalDetails
- * @returns {Array}
- */
-function getIneligibleInvitees(policyMembers, personalDetails) {
- const memberEmailsToExclude = [...CONST.EXPENSIFY_EMAILS];
- _.each(policyMembers, (policyMember, accountID) => {
- // Policy members that are pending delete or have errors are not valid and we should show them in the invite options (don't exclude them).
- if (policyMember.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(policyMember.errors)) {
- return;
- }
- const memberEmail = lodashGet(personalDetails, `[${accountID}].login`);
- if (!memberEmail) {
- return;
- }
- memberEmailsToExclude.push(memberEmail);
- });
-
- return memberEmailsToExclude;
-}
-
-/**
- * Gets the tag from policy tags, defaults to the first if no key is provided.
- *
- * @param {Object} policyTags
- * @param {String} [tagKey]
- * @returns {Object}
- */
-function getTag(policyTags, tagKey) {
- if (_.isEmpty(policyTags)) {
- return {};
- }
-
- const policyTagKey = tagKey || _.first(_.keys(policyTags));
-
- return lodashGet(policyTags, policyTagKey, {});
-}
-
-/**
- * Gets the first tag name from policy tags.
- *
- * @param {Object} policyTags
- * @returns {String}
- */
-function getTagListName(policyTags) {
- if (_.isEmpty(policyTags)) {
- return '';
- }
-
- const policyTagKeys = _.keys(policyTags) || [];
-
- return lodashGet(policyTags, [_.first(policyTagKeys), 'name'], '');
-}
-
-/**
- * Gets the tags of a policy for a specific key. Defaults to the first tag if no key is provided.
- *
- * @param {Object} policyTags
- * @param {String} [tagKey]
- * @returns {String}
- */
-function getTagList(policyTags, tagKey) {
- if (_.isEmpty(policyTags)) {
- return {};
- }
-
- const policyTagKey = tagKey || _.first(_.keys(policyTags));
-
- return lodashGet(policyTags, [policyTagKey, 'tags'], {});
-}
-
-/**
- * @param {Object} policy
- * @returns {Boolean}
- */
-function isPendingDeletePolicy(policy) {
- return policy.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
-}
-
-export {
- getActivePolicies,
- hasPolicyMemberError,
- hasPolicyError,
- hasPolicyErrorFields,
- hasCustomUnitsError,
- getNumericValue,
- getUnitRateValue,
- getPolicyBrickRoadIndicatorStatus,
- shouldShowPolicy,
- isExpensifyTeam,
- isExpensifyGuideTeam,
- isPolicyAdmin,
- getMemberAccountIDsForWorkspace,
- getIneligibleInvitees,
- isPolicyMember,
- getTag,
- getTagListName,
- getTagList,
- isPendingDeletePolicy,
-};
diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts
new file mode 100644
index 000000000000..62640a11311a
--- /dev/null
+++ b/src/libs/PolicyUtils.ts
@@ -0,0 +1,220 @@
+import Str from 'expensify-common/lib/str';
+import {OnyxCollection, OnyxEntry} from 'react-native-onyx';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {PersonalDetails, Policy, PolicyMembers, PolicyTags} from '@src/types/onyx';
+
+type MemberEmailsToAccountIDs = Record;
+type PersonalDetailsList = Record;
+type UnitRate = {rate: number};
+
+/**
+ * Filter out the active policies, which will exclude policies with pending deletion
+ * These are policies that we can use to create reports with in NewDot.
+ */
+function getActivePolicies(policies: OnyxCollection): Policy[] | undefined {
+ return Object.values(policies ?? {}).filter(
+ (policy): policy is Policy =>
+ policy !== null && policy && (policy.isPolicyExpenseChatEnabled || policy.areChatRoomsEnabled) && policy.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
+ );
+}
+
+/**
+ * Checks if we have any errors stored within the POLICY_MEMBERS. Determines whether we should show a red brick road error or not.
+ * Data structure: {accountID: {role:'user', errors: []}, accountID2: {role:'admin', errors: [{1231312313: 'Unable to do X'}]}, ...}
+ */
+function hasPolicyMemberError(policyMembers: OnyxEntry): boolean {
+ return Object.values(policyMembers ?? {}).some((member) => Object.keys(member?.errors ?? {}).length > 0);
+}
+
+/**
+ * Check if the policy has any error fields.
+ */
+function hasPolicyErrorFields(policy: OnyxEntry): boolean {
+ return Object.keys(policy?.errorFields ?? {}).some((fieldErrors) => Object.keys(fieldErrors ?? {}).length > 0);
+}
+
+/**
+ * Check if the policy has any errors, and if it doesn't, then check if it has any error fields.
+ */
+function hasPolicyError(policy: OnyxEntry): boolean {
+ return Object.keys(policy?.errors ?? {}).length > 0 ? true : hasPolicyErrorFields(policy);
+}
+
+/**
+ * Checks if we have any errors stored within the policy custom units.
+ */
+function hasCustomUnitsError(policy: OnyxEntry): boolean {
+ return Object.keys(policy?.customUnits?.errors ?? {}).length > 0;
+}
+
+function getNumericValue(value: number, toLocaleDigit: (arg: string) => string): number | string {
+ const numValue = parseFloat(value.toString().replace(toLocaleDigit('.'), '.'));
+ if (Number.isNaN(numValue)) {
+ return NaN;
+ }
+ return numValue.toFixed(CONST.CUSTOM_UNITS.RATE_DECIMALS);
+}
+
+function getRateDisplayValue(value: number, toLocaleDigit: (arg: string) => string): string {
+ const numValue = getNumericValue(value, toLocaleDigit);
+ if (Number.isNaN(numValue)) {
+ return '';
+ }
+ return numValue.toString().replace('.', toLocaleDigit('.')).substring(0, value.toString().length);
+}
+
+function getUnitRateValue(customUnitRate: UnitRate, toLocaleDigit: (arg: string) => string) {
+ return getRateDisplayValue((customUnitRate?.rate ?? 0) / CONST.POLICY.CUSTOM_UNIT_RATE_BASE_OFFSET, toLocaleDigit);
+}
+
+/**
+ * Get the brick road indicator status for a policy. The policy has an error status if there is a policy member error, a custom unit error or a field error.
+ */
+function getPolicyBrickRoadIndicatorStatus(policy: OnyxEntry, policyMembersCollection: OnyxCollection): string {
+ const policyMembers = policyMembersCollection?.[`${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policy?.id}`] ?? {};
+ if (hasPolicyMemberError(policyMembers) || hasCustomUnitsError(policy) || hasPolicyErrorFields(policy)) {
+ return CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR;
+ }
+ return '';
+}
+
+/**
+ * Check if the policy can be displayed
+ * If offline, always show the policy pending deletion.
+ * If online, show the policy pending deletion only if there is an error.
+ * Note: Using a local ONYXKEYS.NETWORK subscription will cause a delay in
+ * updating the screen. Passing the offline status from the component.
+ */
+function shouldShowPolicy(policy: OnyxEntry, isOffline: boolean): boolean {
+ return (
+ !!policy &&
+ policy?.isPolicyExpenseChatEnabled &&
+ policy?.role === CONST.POLICY.ROLE.ADMIN &&
+ (isOffline || policy?.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || Object.keys(policy.errors ?? {}).length > 0)
+ );
+}
+
+function isExpensifyTeam(email: string): boolean {
+ const emailDomain = Str.extractEmailDomain(email ?? '');
+ return emailDomain === CONST.EXPENSIFY_PARTNER_NAME || emailDomain === CONST.EMAIL.GUIDES_DOMAIN;
+}
+
+function isExpensifyGuideTeam(email: string): boolean {
+ const emailDomain = Str.extractEmailDomain(email ?? '');
+ return emailDomain === CONST.EMAIL.GUIDES_DOMAIN;
+}
+
+/**
+ * Checks if the current user is an admin of the policy.
+ */
+const isPolicyAdmin = (policy: OnyxEntry): boolean => policy?.role === CONST.POLICY.ROLE.ADMIN;
+
+const isPolicyMember = (policyID: string, policies: Record): boolean => Object.values(policies).some((policy) => policy?.id === policyID);
+
+/**
+ * Create an object mapping member emails to their accountIDs. Filter for members without errors, and get the login email from the personalDetail object using the accountID.
+ *
+ * We only return members without errors. Otherwise, the members with errors would immediately be removed before the user has a chance to read the error.
+ */
+function getMemberAccountIDsForWorkspace(policyMembers: OnyxEntry, personalDetails: OnyxEntry): MemberEmailsToAccountIDs {
+ const memberEmailsToAccountIDs: MemberEmailsToAccountIDs = {};
+ Object.keys(policyMembers ?? {}).forEach((accountID) => {
+ const member = policyMembers?.[accountID];
+ if (Object.keys(member?.errors ?? {})?.length > 0) {
+ return;
+ }
+ const personalDetail = personalDetails?.[accountID];
+ if (!personalDetail?.login) {
+ return;
+ }
+ memberEmailsToAccountIDs[personalDetail.login] = Number(accountID);
+ });
+ return memberEmailsToAccountIDs;
+}
+
+/**
+ * Get login list that we should not show in the workspace invite options
+ */
+function getIneligibleInvitees(policyMembers: OnyxEntry, personalDetails: OnyxEntry): string[] {
+ const memberEmailsToExclude: string[] = [...CONST.EXPENSIFY_EMAILS];
+ Object.keys(policyMembers ?? {}).forEach((accountID) => {
+ const policyMember = policyMembers?.[accountID];
+ // Policy members that are pending delete or have errors are not valid and we should show them in the invite options (don't exclude them).
+ if (policyMember?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || Object.keys(policyMember?.errors ?? {}).length > 0) {
+ return;
+ }
+ const memberEmail = personalDetails?.[accountID]?.login;
+ if (!memberEmail) {
+ return;
+ }
+ memberEmailsToExclude.push(memberEmail);
+ });
+
+ return memberEmailsToExclude;
+}
+
+/**
+ * Gets the tag from policy tags, defaults to the first if no key is provided.
+ */
+function getTag(policyTags: OnyxEntry, tagKey?: keyof typeof policyTags) {
+ if (Object.keys(policyTags ?? {})?.length === 0) {
+ return {};
+ }
+
+ const policyTagKey = tagKey ?? Object.keys(policyTags ?? {})[0];
+
+ return policyTags?.[policyTagKey] ?? {};
+}
+
+/**
+ * Gets the first tag name from policy tags.
+ */
+function getTagListName(policyTags: OnyxEntry) {
+ if (Object.keys(policyTags ?? {})?.length === 0) {
+ return '';
+ }
+
+ const policyTagKeys = Object.keys(policyTags ?? {})[0] ?? [];
+
+ return policyTags?.[policyTagKeys]?.name ?? '';
+}
+
+/**
+ * Gets the tags of a policy for a specific key. Defaults to the first tag if no key is provided.
+ */
+function getTagList(policyTags: OnyxCollection, tagKey: string) {
+ if (Object.keys(policyTags ?? {})?.length === 0) {
+ return {};
+ }
+
+ const policyTagKey = tagKey ?? Object.keys(policyTags ?? {})[0];
+
+ return policyTags?.[policyTagKey]?.tags ?? {};
+}
+
+function isPendingDeletePolicy(policy: OnyxEntry): boolean {
+ return policy?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
+}
+
+export {
+ getActivePolicies,
+ hasPolicyMemberError,
+ hasPolicyError,
+ hasPolicyErrorFields,
+ hasCustomUnitsError,
+ getNumericValue,
+ getUnitRateValue,
+ getPolicyBrickRoadIndicatorStatus,
+ shouldShowPolicy,
+ isExpensifyTeam,
+ isExpensifyGuideTeam,
+ isPolicyAdmin,
+ getMemberAccountIDsForWorkspace,
+ getIneligibleInvitees,
+ getTag,
+ getTagListName,
+ getTagList,
+ isPendingDeletePolicy,
+ isPolicyMember,
+};
diff --git a/src/libs/Pusher/pusher.ts b/src/libs/Pusher/pusher.ts
index dad963e933fe..dd8af08db229 100644
--- a/src/libs/Pusher/pusher.ts
+++ b/src/libs/Pusher/pusher.ts
@@ -1,15 +1,15 @@
-import Onyx from 'react-native-onyx';
-import {Channel, ChannelAuthorizerGenerator, Options} from 'pusher-js/with-encryption';
import isObject from 'lodash/isObject';
+import {Channel, ChannelAuthorizerGenerator, Options} from 'pusher-js/with-encryption';
+import Onyx from 'react-native-onyx';
import {LiteralUnion, ValueOf} from 'type-fest';
-import ONYXKEYS from '../../ONYXKEYS';
-import Pusher from './library';
+import Log from '@libs/Log';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {OnyxUpdateEvent, OnyxUpdatesFromServer} from '@src/types/onyx';
+import DeepValueOf from '@src/types/utils/DeepValueOf';
import TYPE from './EventType';
-import Log from '../Log';
-import DeepValueOf from '../../types/utils/DeepValueOf';
+import Pusher from './library';
import {SocketEventName} from './library/types';
-import CONST from '../../CONST';
-import {OnyxUpdateEvent, OnyxUpdatesFromServer} from '../../types/onyx';
type States = {
previous: string;
diff --git a/src/libs/PusherConnectionManager.ts b/src/libs/PusherConnectionManager.ts
index 9b1f6ebe1b2a..a0c5673af729 100644
--- a/src/libs/PusherConnectionManager.ts
+++ b/src/libs/PusherConnectionManager.ts
@@ -1,9 +1,9 @@
import {ChannelAuthorizationCallback} from 'pusher-js/with-encryption';
-import * as Pusher from './Pusher/pusher';
+import CONST from '@src/CONST';
import * as Session from './actions/Session';
import Log from './Log';
-import CONST from '../CONST';
import {SocketEventName} from './Pusher/library/types';
+import * as Pusher from './Pusher/pusher';
import {EventCallbackError, States} from './Pusher/pusher';
function init() {
diff --git a/src/libs/PusherUtils.ts b/src/libs/PusherUtils.ts
index d47283f21bbf..e5782d12acd3 100644
--- a/src/libs/PusherUtils.ts
+++ b/src/libs/PusherUtils.ts
@@ -1,9 +1,9 @@
import {OnyxUpdate} from 'react-native-onyx';
-import CONFIG from '../CONFIG';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
import Log from './Log';
import NetworkConnection from './NetworkConnection';
import * as Pusher from './Pusher/pusher';
-import CONST from '../CONST';
import {PushJSON} from './Pusher/pusher';
type Callback = (data: OnyxUpdate[]) => Promise;
diff --git a/src/libs/ReceiptUtils.ts b/src/libs/ReceiptUtils.ts
index 13e8a195cccb..38b4823d54c6 100644
--- a/src/libs/ReceiptUtils.ts
+++ b/src/libs/ReceiptUtils.ts
@@ -1,13 +1,13 @@
import Str from 'expensify-common/lib/str';
import {ImageSourcePropType} from 'react-native';
+import ReceiptDoc from '@assets/images/receipt-doc.png';
+import ReceiptGeneric from '@assets/images/receipt-generic.png';
+import ReceiptHTML from '@assets/images/receipt-html.png';
+import ReceiptSVG from '@assets/images/receipt-svg.png';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
+import {Transaction} from '@src/types/onyx';
import * as FileUtils from './fileDownload/FileUtils';
-import CONST from '../CONST';
-import ReceiptHTML from '../../assets/images/receipt-html.png';
-import ReceiptDoc from '../../assets/images/receipt-doc.png';
-import ReceiptGeneric from '../../assets/images/receipt-generic.png';
-import ReceiptSVG from '../../assets/images/receipt-svg.png';
-import {Transaction} from '../types/onyx';
-import ROUTES from '../ROUTES';
type ThumbnailAndImageURI = {
image: ImageSourcePropType | string;
diff --git a/src/libs/ReportActionComposeFocusManager.ts b/src/libs/ReportActionComposeFocusManager.ts
index 65466fa4a204..9d4039117989 100644
--- a/src/libs/ReportActionComposeFocusManager.ts
+++ b/src/libs/ReportActionComposeFocusManager.ts
@@ -1,6 +1,6 @@
import React from 'react';
import {TextInput} from 'react-native';
-import ROUTES from '../ROUTES';
+import ROUTES from '@src/ROUTES';
import Navigation from './Navigation/Navigation';
type FocusCallback = () => void;
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 98a029bde5de..11e11f549682 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -2,15 +2,15 @@ import _ from 'lodash';
import lodashFindLast from 'lodash/findLast';
import Onyx, {OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
import {ValueOf} from 'type-fest';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import ReportAction, {ReportActions} from '../types/onyx/ReportAction';
-import Report from '../types/onyx/Report';
-import {ActionName} from '../types/onyx/OriginalMessage';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {ActionName} from '@src/types/onyx/OriginalMessage';
+import Report from '@src/types/onyx/Report';
+import ReportAction, {ReportActions} from '@src/types/onyx/ReportAction';
import * as CollectionUtils from './CollectionUtils';
-import Log from './Log';
-import isReportMessageAttachment from './isReportMessageAttachment';
import * as Environment from './Environment/Environment';
+import isReportMessageAttachment from './isReportMessageAttachment';
+import Log from './Log';
type LastVisibleMessage = {
lastMessageTranslationKey?: string;
@@ -267,7 +267,7 @@ function isConsecutiveActionMadeByPreviousActor(reportActions: ReportAction[] |
/**
* Checks if a reportAction is deprecated.
*/
-function isReportActionDeprecated(reportAction: OnyxEntry, key: string): boolean {
+function isReportActionDeprecated(reportAction: OnyxEntry, key: string | number): boolean {
if (!reportAction) {
return true;
}
@@ -289,7 +289,7 @@ const supportedActionTypes: ActionName[] = [...Object.values(otherActionTypes),
* Checks if a reportAction is fit for display, meaning that it's not deprecated, is of a valid
* and supported type, it's not deleted and also not closed.
*/
-function shouldReportActionBeVisible(reportAction: OnyxEntry, key: string): boolean {
+function shouldReportActionBeVisible(reportAction: OnyxEntry, key: string | number): boolean {
if (!reportAction) {
return false;
}
diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js
index 7a67d28816d7..0e9091fd6cb2 100644
--- a/src/libs/ReportUtils.js
+++ b/src/libs/ReportUtils.js
@@ -1,27 +1,27 @@
/* eslint-disable rulesdir/prefer-underscore-method */
-import _ from 'underscore';
import {format} from 'date-fns';
+import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import lodashIntersection from 'lodash/intersection';
import Onyx from 'react-native-onyx';
-import ExpensiMark from 'expensify-common/lib/ExpensiMark';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
+import _ from 'underscore';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as defaultWorkspaceAvatars from '@components/Icon/WorkspaceDefaultAvatars';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import * as CurrencyUtils from './CurrencyUtils';
+import DateUtils from './DateUtils';
+import isReportMessageAttachment from './isReportMessageAttachment';
import * as Localize from './Localize';
-import * as Expensicons from '../components/Icon/Expensicons';
+import linkingConfig from './Navigation/linkingConfig';
import Navigation from './Navigation/Navigation';
-import ROUTES from '../ROUTES';
import * as NumberUtils from './NumberUtils';
+import Permissions from './Permissions';
import * as ReportActionsUtils from './ReportActionsUtils';
import * as TransactionUtils from './TransactionUtils';
import * as Url from './Url';
-import Permissions from './Permissions';
-import DateUtils from './DateUtils';
-import linkingConfig from './Navigation/linkingConfig';
-import isReportMessageAttachment from './isReportMessageAttachment';
-import * as defaultWorkspaceAvatars from '../components/Icon/WorkspaceDefaultAvatars';
-import * as CurrencyUtils from './CurrencyUtils';
import * as UserUtils from './UserUtils';
let currentUserEmail;
@@ -108,9 +108,9 @@ function getPolicyType(report, policies) {
/**
* Get the policy name from a given report
* @param {Object} report
- * @param {String} report.policyID
- * @param {String} report.oldPolicyName
- * @param {String} report.policyName
+ * @param {String} [report.policyID]
+ * @param {String} [report.oldPolicyName]
+ * @param {String} [report.policyName]
* @param {Boolean} [returnEmptyIfNotFound]
* @param {Object} [policy]
* @returns {String}
@@ -369,7 +369,7 @@ function isUserCreatedPolicyRoom(report) {
/**
* Whether the provided report is a Policy Expense chat.
* @param {Object} report
- * @param {String} report.chatType
+ * @param {String} [report.chatType]
* @returns {Boolean}
*/
function isPolicyExpenseChat(report) {
@@ -395,7 +395,7 @@ function isControlPolicyExpenseReport(report) {
/**
* Whether the provided report is a chat room
* @param {Object} report
- * @param {String} report.chatType
+ * @param {String} [report.chatType]
* @returns {Boolean}
*/
function isChatRoom(report) {
@@ -584,8 +584,8 @@ function findLastAccessedReport(reports, ignoreDomainRooms, policies, isFirstTim
/**
* Whether the provided report is an archived room
* @param {Object} report
- * @param {Number} report.stateNum
- * @param {Number} report.statusNum
+ * @param {Number} [report.stateNum]
+ * @param {Number} [report.statusNum]
* @returns {Boolean}
*/
function isArchivedRoom(report) {
@@ -783,6 +783,16 @@ function getReport(reportID) {
return lodashGet(allReports, `${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {}) || {};
}
+/**
+ * Returns whether or not the author of the action is this user
+ *
+ * @param {Object} reportAction
+ * @returns {Boolean}
+ */
+function isActionCreator(reportAction) {
+ return reportAction.actorAccountID === currentUserAccountID;
+}
+
/**
* Can only delete if the author is this user and the action is an ADDCOMMENT action or an IOU action in an unsettled report, or if the user is a
* policy admin
@@ -2468,6 +2478,7 @@ function getIOUReportActionMessage(iouReportID, type, total, comment, currency,
* @param {Boolean} [isSendMoneyFlow] - Whether this is send money flow
* @param {Object} [receipt]
* @param {Boolean} [isOwnPolicyExpenseChat] - Whether this is an expense report create from the current user's policy expense chat
+ * @param {String} [created] - Action created time
* @returns {Object}
*/
function buildOptimisticIOUReportAction(
@@ -2483,6 +2494,7 @@ function buildOptimisticIOUReportAction(
isSendMoneyFlow = false,
receipt = {},
isOwnPolicyExpenseChat = false,
+ created = DateUtils.getDBTime(),
) {
const IOUReportID = iouReportID || generateReportID();
@@ -2540,7 +2552,7 @@ function buildOptimisticIOUReportAction(
],
reportActionID: NumberUtils.rand64(),
shouldShow: true,
- created: DateUtils.getDBTime(),
+ created,
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
whisperedToAccountIDs: _.contains([CONST.IOU.RECEIPT_STATE.SCANREADY, CONST.IOU.RECEIPT_STATE.SCANNING], receipt.state) ? [currentUserAccountID] : [],
};
@@ -2849,9 +2861,10 @@ function buildOptimisticChatReport(
/**
* Returns the necessary reportAction onyx data to indicate that the chat has been created optimistically
* @param {String} emailCreatingAction
+ * @param {String} [created] - Action created time
* @returns {Object}
*/
-function buildOptimisticCreatedReportAction(emailCreatingAction) {
+function buildOptimisticCreatedReportAction(emailCreatingAction, created = DateUtils.getDBTime()) {
return {
reportActionID: NumberUtils.rand64(),
actionName: CONST.REPORT.ACTIONS.TYPE.CREATED,
@@ -2878,7 +2891,7 @@ function buildOptimisticCreatedReportAction(emailCreatingAction) {
],
automatic: false,
avatar: lodashGet(allPersonalDetails, [currentUserAccountID, 'avatar'], UserUtils.getDefaultAvatar(currentUserAccountID)),
- created: DateUtils.getDBTime(),
+ created,
shouldShow: true,
};
}
@@ -3203,8 +3216,8 @@ function canSeeDefaultRoom(report, policies, betas) {
/**
* @param {Object} report
- * @param {Array} policies
- * @param {Array} betas
+ * @param {Object | null} policies
+ * @param {Array | null} betas
* @param {Object} allReportActions
* @returns {Boolean}
*/
@@ -3241,7 +3254,7 @@ function shouldHideReport(report, currentReportId) {
* filter out the majority of reports before filtering out very specific minority of reports.
*
* @param {Object} report
- * @param {String} currentReportId
+ * @param {String | Null | Undefined} currentReportId
* @param {Boolean} isInGSDMode
* @param {String[]} betas
* @param {Object} policies
@@ -3259,6 +3272,7 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas,
!report ||
!report.reportID ||
!report.type ||
+ report.reportName === undefined ||
report.isHidden ||
(report.participantAccountIDs &&
report.participantAccountIDs.length === 0 &&
@@ -3295,6 +3309,11 @@ function shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas,
return true;
}
+ // Hide only chat threads that haven't been commented on (other threads are actionable)
+ if (isChatThread(report) && canHideReport && isEmptyChat) {
+ return false;
+ }
+
// Include reports that have errors from trying to add a workspace
// If we excluded it, then the red-brock-road pattern wouldn't work for the user to resolve the error
if (report.errorFields && report.errorFields.addWorkspaceRoom) {
@@ -4112,6 +4131,7 @@ export {
canEditReportAction,
canFlagReportAction,
shouldShowFlagComment,
+ isActionCreator,
canDeleteReportAction,
canLeaveRoom,
sortReportsByLastRead,
diff --git a/src/libs/Request.ts b/src/libs/Request.ts
index 9c4af4aa7e18..335731763ec9 100644
--- a/src/libs/Request.ts
+++ b/src/libs/Request.ts
@@ -1,9 +1,9 @@
+import Request from '@src/types/onyx/Request';
+import Response from '@src/types/onyx/Response';
import HttpUtils from './HttpUtils';
+import Middleware from './Middleware/types';
import enhanceParameters from './Network/enhanceParameters';
import * as NetworkStore from './Network/NetworkStore';
-import Request from '../types/onyx/Request';
-import Response from '../types/onyx/Response';
-import Middleware from './Middleware/types';
let middlewares: Middleware[] = [];
diff --git a/src/libs/RequestThrottle.ts b/src/libs/RequestThrottle.ts
index 00dca2ebf61e..36935982afbb 100644
--- a/src/libs/RequestThrottle.ts
+++ b/src/libs/RequestThrottle.ts
@@ -1,4 +1,4 @@
-import CONST from '../CONST';
+import CONST from '@src/CONST';
import {generateRandomInt} from './NumberUtils';
let requestWaitTime = 0;
diff --git a/src/libs/RoomNameInputUtils.ts b/src/libs/RoomNameInputUtils.ts
index 2777acee45dd..cff0bbc30274 100644
--- a/src/libs/RoomNameInputUtils.ts
+++ b/src/libs/RoomNameInputUtils.ts
@@ -1,4 +1,4 @@
-import CONST from '../CONST';
+import CONST from '@src/CONST';
/**
* Replaces spaces with dashes
diff --git a/src/libs/SelectionScraper/index.js b/src/libs/SelectionScraper/index.js
index 44b87deba796..02b3ff8bf61b 100644
--- a/src/libs/SelectionScraper/index.js
+++ b/src/libs/SelectionScraper/index.js
@@ -1,8 +1,8 @@
import render from 'dom-serializer';
+import Str from 'expensify-common/lib/str';
import {parseDocument} from 'htmlparser2';
import _ from 'underscore';
-import Str from 'expensify-common/lib/str';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
const elementsWillBeSkipped = ['html', 'body'];
const tagAttribute = 'data-testid';
diff --git a/src/libs/SessionUtils.ts b/src/libs/SessionUtils.ts
index fcbc9a887fa9..6cd20e0b56b2 100644
--- a/src/libs/SessionUtils.ts
+++ b/src/libs/SessionUtils.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Determine if the transitioning user is logging in as a new user.
diff --git a/src/libs/SidebarUtils.js b/src/libs/SidebarUtils.ts
similarity index 58%
rename from src/libs/SidebarUtils.js
rename to src/libs/SidebarUtils.ts
index bd3d730edc0c..79d3280e859e 100644
--- a/src/libs/SidebarUtils.js
+++ b/src/libs/SidebarUtils.ts
@@ -1,21 +1,27 @@
/* eslint-disable rulesdir/prefer-underscore-method */
-import Onyx from 'react-native-onyx';
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
import Str from 'expensify-common/lib/str';
-import ONYXKEYS from '../ONYXKEYS';
-import * as ReportUtils from './ReportUtils';
-import * as ReportActionsUtils from './ReportActionsUtils';
-import * as Localize from './Localize';
-import CONST from '../CONST';
-import * as OptionsListUtils from './OptionsListUtils';
+import Onyx from 'react-native-onyx';
+import {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {PersonalDetails} from '@src/types/onyx';
+import Beta from '@src/types/onyx/Beta';
+import * as OnyxCommon from '@src/types/onyx/OnyxCommon';
+import Policy from '@src/types/onyx/Policy';
+import Report from '@src/types/onyx/Report';
+import ReportAction, {ReportActions} from '@src/types/onyx/ReportAction';
import * as CollectionUtils from './CollectionUtils';
import * as LocalePhoneNumber from './LocalePhoneNumber';
-import * as UserUtils from './UserUtils';
+import * as Localize from './Localize';
+import * as OptionsListUtils from './OptionsListUtils';
import * as PersonalDetailsUtils from './PersonalDetailsUtils';
+import * as ReportActionsUtils from './ReportActionsUtils';
+import * as ReportUtils from './ReportUtils';
+import * as UserUtils from './UserUtils';
+
+const visibleReportActionItems: ReportActions = {};
+const lastReportActions: ReportActions = {};
-const visibleReportActionItems = {};
-const lastReportActions = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT_ACTIONS,
callback: (actions, key) => {
@@ -24,38 +30,37 @@ Onyx.connect({
}
const reportID = CollectionUtils.extractCollectionItemID(key);
- const actionsArray = ReportActionsUtils.getSortedReportActions(_.toArray(actions));
- lastReportActions[reportID] = _.last(actionsArray);
+ const actionsArray: ReportAction[] = ReportActionsUtils.getSortedReportActions(Object.values(actions));
+ lastReportActions[reportID] = actionsArray[actionsArray.length - 1];
// The report is only visible if it is the last action not deleted that
// does not match a closed or created state.
- const reportActionsForDisplay = _.filter(
- actionsArray,
+ const reportActionsForDisplay = actionsArray.filter(
(reportAction, actionKey) =>
ReportActionsUtils.shouldReportActionBeVisible(reportAction, actionKey) &&
reportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED &&
reportAction.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
);
- visibleReportActionItems[reportID] = _.last(reportActionsForDisplay);
+ visibleReportActionItems[reportID] = reportActionsForDisplay[reportActionsForDisplay.length - 1];
},
});
// Session can remain stale because the only way for the current user to change is to
// sign out and sign in, which would clear out all the Onyx
// data anyway and cause SidebarLinks to rerender.
-let currentUserAccountID;
+let currentUserAccountID: number | undefined;
Onyx.connect({
key: ONYXKEYS.SESSION,
- callback: (val) => {
- if (!val) {
+ callback: (session) => {
+ if (!session) {
return;
}
- currentUserAccountID = val.accountID;
+ currentUserAccountID = session.accountID;
},
});
-let resolveSidebarIsReadyPromise;
+let resolveSidebarIsReadyPromise: (args?: unknown[]) => void;
let sidebarIsReadyPromise = new Promise((resolve) => {
resolveSidebarIsReadyPromise = resolve;
@@ -67,15 +72,15 @@ function resetIsSidebarLoadedReadyPromise() {
});
}
-function isSidebarLoadedReady() {
+function isSidebarLoadedReady(): Promise {
return sidebarIsReadyPromise;
}
-function compareStringDates(stringA, stringB) {
- if (stringA < stringB) {
+function compareStringDates(a: string, b: string): 0 | 1 | -1 {
+ if (a < b) {
return -1;
}
- if (stringA > stringB) {
+ if (a > b) {
return 1;
}
return 0;
@@ -86,10 +91,10 @@ function setIsSidebarLoadedReady() {
}
// Define a cache object to store the memoized results
-const reportIDsCache = new Map();
+const reportIDsCache = new Map();
// Function to set a key-value pair while maintaining the maximum key limit
-function setWithLimit(map, key, value) {
+function setWithLimit(map: Map, key: TKey, value: TValue) {
if (map.size >= 5) {
// If the map has reached its limit, remove the first (oldest) key-value pair
const firstKey = map.keys().next().value;
@@ -102,20 +107,20 @@ function setWithLimit(map, key, value) {
let hasInitialReportActions = false;
/**
- * @param {String} currentReportId
- * @param {Object} allReportsDict
- * @param {Object} betas
- * @param {String[]} policies
- * @param {String} priorityMode
- * @param {Object} allReportActions
- * @returns {String[]} An array of reportIDs sorted in the proper order
+ * @returns An array of reportIDs sorted in the proper order
*/
-function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions) {
+function getOrderedReportIDs(
+ currentReportId: string | null,
+ allReports: Record,
+ betas: Beta[],
+ policies: Record,
+ priorityMode: ValueOf,
+ allReportActions: Record,
+): string[] {
// Generate a unique cache key based on the function arguments
const cachedReportsKey = JSON.stringify(
- // eslint-disable-next-line es/no-optional-chaining
- [currentReportId, allReportsDict, betas, policies, priorityMode, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1],
- (key, value) => {
+ [currentReportId, allReports, betas, policies, priorityMode, allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${currentReportId}`]?.length || 1],
+ (key, value: unknown) => {
/**
* Exclude 'participantAccountIDs', 'participants' and 'lastMessageText' not to overwhelm a cached key value with huge data,
* which we don't need to store in a cacheKey
@@ -123,13 +128,15 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p
if (key === 'participantAccountIDs' || key === 'participants' || key === 'lastMessageText') {
return undefined;
}
+
return value;
},
);
// Check if the result is already in the cache
- if (reportIDsCache.has(cachedReportsKey) && hasInitialReportActions) {
- return reportIDsCache.get(cachedReportsKey);
+ const cachedIDs = reportIDsCache.get(cachedReportsKey);
+ if (cachedIDs && hasInitialReportActions) {
+ return cachedIDs;
}
// This is needed to prevent caching when Onyx is empty for a second render
@@ -137,7 +144,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p
const isInGSDMode = priorityMode === CONST.PRIORITY_MODE.GSD;
const isInDefaultMode = !isInGSDMode;
- const allReportsDictValues = Object.values(allReportsDict);
+ const allReportsDictValues = Object.values(allReports);
// Filter out all the reports that shouldn't be displayed
const reportsToDisplay = allReportsDictValues.filter((report) => ReportUtils.shouldReportBeInOptionList(report, currentReportId, isInGSDMode, betas, policies, allReportActions, true));
@@ -158,7 +165,7 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p
report.displayName = ReportUtils.getReportName(report);
// eslint-disable-next-line no-param-reassign
- report.iouReportAmount = ReportUtils.getMoneyRequestReimbursableTotal(report, allReportsDict);
+ report.iouReportAmount = ReportUtils.getMoneyRequestReimbursableTotal(report, allReports);
});
// The LHN is split into five distinct groups, and each group is sorted a little differently. The groups will ALWAYS be in this order:
@@ -171,11 +178,11 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p
// 5. Archived reports
// - Sorted by lastVisibleActionCreated in default (most recent) view mode
// - Sorted by reportDisplayName in GSD (focus) view mode
- const pinnedReports = [];
- const outstandingIOUReports = [];
- const draftReports = [];
- const nonArchivedReports = [];
- const archivedReports = [];
+ const pinnedReports: Report[] = [];
+ const outstandingIOUReports: Report[] = [];
+ const draftReports: Report[] = [];
+ const nonArchivedReports: Report[] = [];
+ const archivedReports: Report[] = [];
reportsToDisplay.forEach((report) => {
if (report.isPinned) {
pinnedReports.push(report);
@@ -191,47 +198,121 @@ function getOrderedReportIDs(currentReportId, allReportsDict, betas, policies, p
});
// Sort each group of reports accordingly
- pinnedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()));
- outstandingIOUReports.sort((a, b) => b.iouReportAmount - a.iouReportAmount || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()));
- draftReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()));
+ pinnedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0));
+ outstandingIOUReports.sort((a, b) => {
+ const compareAmounts = a?.iouReportAmount && b?.iouReportAmount ? b.iouReportAmount - a.iouReportAmount : 0;
+ const compareDisplayNames = a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0;
+ return compareAmounts || compareDisplayNames;
+ });
+ draftReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0));
if (isInDefaultMode) {
- nonArchivedReports.sort(
- (a, b) => compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) || a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()),
- );
+ nonArchivedReports.sort((a, b) => {
+ const compareDates = a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0;
+ const compareDisplayNames = a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0;
+ return compareDates || compareDisplayNames;
+ });
// For archived reports ensure that most recent reports are at the top by reversing the order
- archivedReports.sort((a, b) => compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated));
+ archivedReports.sort((a, b) => (a?.lastVisibleActionCreated && b?.lastVisibleActionCreated ? compareStringDates(b.lastVisibleActionCreated, a.lastVisibleActionCreated) : 0));
} else {
- nonArchivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()));
- archivedReports.sort((a, b) => a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()));
+ nonArchivedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0));
+ archivedReports.sort((a, b) => (a?.displayName && b?.displayName ? a.displayName.toLowerCase().localeCompare(b.displayName.toLowerCase()) : 0));
}
// Now that we have all the reports grouped and sorted, they must be flattened into an array and only return the reportID.
// The order the arrays are concatenated in matters and will determine the order that the groups are displayed in the sidebar.
- const LHNReports = [].concat(pinnedReports, outstandingIOUReports, draftReports, nonArchivedReports, archivedReports).map((report) => report.reportID);
+ const LHNReports = [...pinnedReports, ...outstandingIOUReports, ...draftReports, ...nonArchivedReports, ...archivedReports].map((report) => report.reportID);
setWithLimit(reportIDsCache, cachedReportsKey, LHNReports);
return LHNReports;
}
+type OptionData = {
+ text?: string | null;
+ alternateText?: string | null;
+ pendingAction?: OnyxCommon.PendingAction | null;
+ allReportErrors?: OnyxCommon.Errors | null;
+ brickRoadIndicator?: typeof CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR | '' | null;
+ icons?: Icon[] | null;
+ tooltipText?: string | null;
+ ownerAccountID?: number | null;
+ subtitle?: string | null;
+ participantsList?: PersonalDetails[] | null;
+ login?: string | null;
+ accountID?: number | null;
+ managerID?: number | null;
+ reportID?: string | null;
+ policyID?: string | null;
+ status?: string | null;
+ type?: string | null;
+ stateNum?: ValueOf | null;
+ statusNum?: ValueOf | null;
+ phoneNumber?: string | null;
+ isUnread?: boolean | null;
+ isUnreadWithMention?: boolean | null;
+ hasDraftComment?: boolean | null;
+ keyForList?: string | null;
+ searchText?: string | null;
+ isPinned?: boolean | null;
+ hasOutstandingIOU?: boolean | null;
+ iouReportID?: string | null;
+ isIOUReportOwner?: boolean | null;
+ iouReportAmount?: number | null;
+ isChatRoom?: boolean | null;
+ isArchivedRoom?: boolean | null;
+ shouldShowSubscript?: boolean | null;
+ isPolicyExpenseChat?: boolean | null;
+ isMoneyRequestReport?: boolean | null;
+ isExpenseRequest?: boolean | null;
+ isWaitingOnBankAccount?: boolean | null;
+ isAllowedToComment?: boolean | null;
+ isThread?: boolean | null;
+ isTaskReport?: boolean | null;
+ isWaitingForTaskCompleteFromAssignee?: boolean | null;
+ parentReportID?: string | null;
+ notificationPreference?: string | number | null;
+ displayNamesWithTooltips?: DisplayNamesWithTooltip[] | null;
+ chatType?: ValueOf | null;
+};
+
+type DisplayNamesWithTooltip = {
+ displayName?: string;
+ avatar?: string;
+ login?: string;
+ accountID?: number;
+ pronouns?: string;
+};
+
+type ActorDetails = {
+ displayName?: string;
+ accountID?: number;
+};
+
+type Icon = {
+ source?: string;
+ id?: number;
+ type?: string;
+ name?: string;
+};
+
/**
* Gets all the data necessary for rendering an OptionRowLHN component
- *
- * @param {Object} report
- * @param {Object} reportActions
- * @param {Object} personalDetails
- * @param {String} preferredLocale
- * @param {Object} [policy]
- * @param {Object} parentReportAction
- * @returns {Object}
*/
-function getOptionData(report, reportActions, personalDetails, preferredLocale, policy, parentReportAction) {
+function getOptionData(
+ report: Report,
+ reportActions: Record,
+ personalDetails: Record,
+ preferredLocale: ValueOf,
+ policy: Policy,
+ parentReportAction: ReportAction,
+): OptionData | undefined {
// When a user signs out, Onyx is cleared. Due to the lazy rendering with a virtual list, it's possible for
// this method to be called after the Onyx data has been cleared out. In that case, it's fine to do
// a null check here and return early.
if (!report || !personalDetails) {
return;
}
- const result = {
+
+ const result: OptionData = {
text: null,
alternateText: null,
pendingAction: null,
@@ -268,10 +349,10 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale,
isExpenseRequest: false,
isWaitingOnBankAccount: false,
isAllowedToComment: true,
+ chatType: null,
};
-
- const participantPersonalDetailList = _.values(OptionsListUtils.getPersonalDetailsForAccountIDs(report.participantAccountIDs, personalDetails));
- const personalDetail = participantPersonalDetailList[0] || {};
+ const participantPersonalDetailList: PersonalDetails[] = Object.values(OptionsListUtils.getPersonalDetailsForAccountIDs(report.participantAccountIDs ?? [], personalDetails));
+ const personalDetail = participantPersonalDetailList[0] ?? {};
result.isThread = ReportUtils.isChatThread(report);
result.isChatRoom = ReportUtils.isChatRoom(report);
@@ -285,8 +366,8 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale,
result.isMoneyRequestReport = ReportUtils.isMoneyRequestReport(report);
result.shouldShowSubscript = ReportUtils.shouldReportShowSubscript(report);
result.pendingAction = report.pendingFields ? report.pendingFields.addWorkspaceRoom || report.pendingFields.createChat : null;
- result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions);
- result.brickRoadIndicator = !_.isEmpty(result.allReportErrors) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '';
+ result.allReportErrors = OptionsListUtils.getAllReportErrors(report, reportActions) as OnyxCommon.Errors;
+ result.brickRoadIndicator = Object.keys(result.allReportErrors ?? {}).length !== 0 ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '';
result.ownerAccountID = report.ownerAccountID;
result.managerID = report.managerID;
result.reportID = report.reportID;
@@ -299,30 +380,31 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale,
result.isPinned = report.isPinned;
result.iouReportID = report.iouReportID;
result.keyForList = String(report.reportID);
- result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs || []);
+ result.tooltipText = ReportUtils.getReportParticipantsTitle(report.participantAccountIDs ?? []);
result.hasOutstandingIOU = report.hasOutstandingIOU;
- result.parentReportID = report.parentReportID || null;
+ result.parentReportID = report.parentReportID ?? null;
result.isWaitingOnBankAccount = report.isWaitingOnBankAccount;
- result.notificationPreference = report.notificationPreference || null;
+ result.notificationPreference = report.notificationPreference ?? null;
result.isAllowedToComment = !ReportUtils.shouldDisableWriteActions(report);
+ result.chatType = report.chatType;
const hasMultipleParticipants = participantPersonalDetailList.length > 1 || result.isChatRoom || result.isPolicyExpenseChat;
const subtitle = ReportUtils.getChatRoomSubtitle(report);
- const login = Str.removeSMSDomain(lodashGet(personalDetail, 'login', ''));
- const status = lodashGet(personalDetail, 'status', '');
+ const login = Str.removeSMSDomain(personalDetail?.login ?? '');
+ const status = personalDetail?.status ?? '';
const formattedLogin = Str.isSMSLogin(login) ? LocalePhoneNumber.formatPhoneNumber(login) : login;
// We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade.
- const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants);
+ const displayNamesWithTooltips: DisplayNamesWithTooltip[] = ReportUtils.getDisplayNamesWithTooltips((participantPersonalDetailList || []).slice(0, 10), hasMultipleParticipants);
const lastMessageTextFromReport = OptionsListUtils.getLastMessageTextForReport(report);
// If the last actor's details are not currently saved in Onyx Collection,
// then try to get that from the last report action if that action is valid
// to get data from.
- let lastActorDetails = personalDetails[report.lastActorAccountID] || null;
+ let lastActorDetails: ActorDetails | null = report.lastActorAccountID && personalDetails?.[report.lastActorAccountID] ? personalDetails[report.lastActorAccountID] : null;
if (!lastActorDetails && visibleReportActionItems[report.reportID]) {
- const lastActorDisplayName = lodashGet(visibleReportActionItems[report.reportID], 'person[0].text');
+ const lastActorDisplayName = visibleReportActionItems[report.reportID]?.person?.[0]?.text;
lastActorDetails = lastActorDisplayName
? {
displayName: lastActorDisplayName,
@@ -330,42 +412,35 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale,
}
: null;
}
- const lastActorDisplayName =
- hasMultipleParticipants && lastActorDetails && lastActorDetails.accountID && Number(lastActorDetails.accountID) !== currentUserAccountID ? lastActorDetails.displayName : '';
+ const lastActorDisplayName = hasMultipleParticipants && lastActorDetails?.accountID && Number(lastActorDetails.accountID) !== currentUserAccountID ? lastActorDetails.displayName : '';
let lastMessageText = lastMessageTextFromReport;
+ const reportAction = lastReportActions?.[report.reportID];
if (result.isArchivedRoom) {
- const archiveReason =
- (lastReportActions[report.reportID] && lastReportActions[report.reportID].originalMessage && lastReportActions[report.reportID].originalMessage.reason) ||
- CONST.REPORT.ARCHIVE_REASON.DEFAULT;
+ const archiveReason = (reportAction?.actionName === CONST.REPORT.ACTIONS.TYPE.CLOSED && reportAction?.originalMessage?.reason) || CONST.REPORT.ARCHIVE_REASON.DEFAULT;
lastMessageText = Localize.translate(preferredLocale, `reportArchiveReasons.${archiveReason}`, {
- displayName: archiveReason.displayName || PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'),
+ displayName: PersonalDetailsUtils.getDisplayNameOrDefault(lastActorDetails, 'displayName'),
policyName: ReportUtils.getPolicyName(report, false, policy),
});
}
if ((result.isChatRoom || result.isPolicyExpenseChat || result.isThread || result.isTaskReport) && !result.isArchivedRoom) {
const lastAction = visibleReportActionItems[report.reportID];
- if (lastAction && lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) {
- const newName = lodashGet(lastAction, 'originalMessage.newName', '');
+
+ if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.RENAMED) {
+ const newName = lastAction?.originalMessage?.newName ?? '';
result.alternateText = Localize.translate(preferredLocale, 'newRoomPage.roomRenamedTo', {newName});
- } else if (lastAction && lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.TASKREOPENED) {
+ } else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.TASKREOPENED) {
result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.reopened')}`;
- } else if (lastAction && lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED) {
+ } else if (lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.TASKCOMPLETED) {
result.alternateText = `${Localize.translate(preferredLocale, 'task.messages.completed')}`;
} else if (
- lastAction &&
- _.includes(
- [
- CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM,
- CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.REMOVE_FROM_ROOM,
- CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM,
- CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.REMOVE_FROM_ROOM,
- ],
- lastAction.actionName,
- )
+ lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM ||
+ lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.REMOVE_FROM_ROOM ||
+ lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM ||
+ lastAction?.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.REMOVE_FROM_ROOM
) {
- const targetAccountIDs = lodashGet(lastAction, 'originalMessage.targetAccountIDs', []);
+ const targetAccountIDs = lastAction?.originalMessage?.targetAccountIDs ?? [];
const verb =
lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM
? 'invited'
@@ -373,7 +448,7 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale,
const users = targetAccountIDs.length > 1 ? 'users' : 'user';
result.alternateText = `${verb} ${targetAccountIDs.length} ${users}`;
- const roomName = lodashGet(lastAction, 'originalMessage.roomName', '');
+ const roomName = lastAction?.originalMessage?.roomName ?? '';
if (roomName) {
const preposition =
lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.ROOMCHANGELOG.INVITE_TO_ROOM || lastAction.actionName === CONST.REPORT.ACTIONS.TYPE.POLICYCHANGELOG.INVITE_TO_ROOM
@@ -381,7 +456,7 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale,
: ' from';
result.alternateText += `${preposition} ${roomName}`;
}
- } else if (lastAction && lastAction.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastActorDisplayName && lastMessageTextFromReport) {
+ } else if (lastAction?.actionName !== CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW && lastActorDisplayName && lastMessageTextFromReport) {
result.alternateText = `${lastActorDisplayName}: ${lastMessageText}`;
} else {
result.alternateText = lastAction && lastMessageTextFromReport.length > 0 ? lastMessageText : Localize.translate(preferredLocale, 'report.noActivityYet');
@@ -392,19 +467,23 @@ function getOptionData(report, reportActions, personalDetails, preferredLocale,
// We also add a fullstop after the final name, the word "and" before the final name and commas between all previous names.
lastMessageText =
Localize.translate(preferredLocale, 'reportActionsView.beginningOfChatHistory') +
- _.map(displayNamesWithTooltips, ({displayName, pronouns}, index) => {
- const formattedText = _.isEmpty(pronouns) ? displayName : `${displayName} (${pronouns})`;
-
- if (index === displayNamesWithTooltips.length - 1) {
- return `${formattedText}.`;
- }
- if (index === displayNamesWithTooltips.length - 2) {
- return `${formattedText} ${Localize.translate(preferredLocale, 'common.and')}`;
- }
- if (index < displayNamesWithTooltips.length - 2) {
- return `${formattedText},`;
- }
- }).join(' ');
+ displayNamesWithTooltips
+ .map(({displayName, pronouns}, index) => {
+ const formattedText = !pronouns ? displayName : `${displayName} (${pronouns})`;
+
+ if (index === displayNamesWithTooltips.length - 1) {
+ return `${formattedText}.`;
+ }
+ if (index === displayNamesWithTooltips.length - 2) {
+ return `${formattedText} ${Localize.translate(preferredLocale, 'common.and')}`;
+ }
+ if (index < displayNamesWithTooltips.length - 2) {
+ return `${formattedText},`;
+ }
+
+ return '';
+ })
+ .join(' ');
}
result.alternateText = lastMessageText || formattedLogin;
diff --git a/src/libs/StartupTimer/index.ts b/src/libs/StartupTimer/index.ts
index 421524a70fc8..1cc656b329f4 100644
--- a/src/libs/StartupTimer/index.ts
+++ b/src/libs/StartupTimer/index.ts
@@ -1,7 +1,6 @@
/**
* Web noop as there is no "startup" to time from the native layer.
*/
-
import StartupTimer from './types';
const startupTimer: StartupTimer = {
diff --git a/src/libs/StringUtils.ts b/src/libs/StringUtils.ts
index 8ef23bb0751b..290380ce2cff 100644
--- a/src/libs/StringUtils.ts
+++ b/src/libs/StringUtils.ts
@@ -1,5 +1,5 @@
import _ from 'lodash';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
/**
* Removes diacritical marks and non-alphabetic and non-latin characters from a string.
diff --git a/src/libs/SuggestionUtils.js b/src/libs/SuggestionUtils.js
index 9c3e92799334..45641ebb5a0f 100644
--- a/src/libs/SuggestionUtils.js
+++ b/src/libs/SuggestionUtils.js
@@ -1,4 +1,4 @@
-import CONST from '../CONST';
+import CONST from '@src/CONST';
/**
* Return the max available index for arrow manager.
diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts
index 44f8094ca13d..a30ba7fc2723 100644
--- a/src/libs/TransactionUtils.ts
+++ b/src/libs/TransactionUtils.ts
@@ -1,12 +1,12 @@
-import Onyx, {OnyxCollection} from 'react-native-onyx';
import {format, isValid} from 'date-fns';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import DateUtils from './DateUtils';
+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 {RecentWaypoint, ReportAction, Transaction} from '../types/onyx';
-import {Receipt, Comment, WaypointCollection, Waypoint} from '../types/onyx/Transaction';
type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection};
@@ -396,9 +396,6 @@ function getAllReportTransactions(reportID?: string): Transaction[] {
return transactions.filter((transaction) => `${transaction.reportID}` === `${reportID}`);
}
-/**
- * Checks if a waypoint has a valid address
- */
function waypointHasValidAddress(waypoint: RecentWaypoint | Waypoint): boolean {
return !!waypoint?.address?.trim();
}
diff --git a/src/libs/UnreadIndicatorUpdater/index.js b/src/libs/UnreadIndicatorUpdater/index.js
index 09fa82612314..9af74f8313c3 100644
--- a/src/libs/UnreadIndicatorUpdater/index.js
+++ b/src/libs/UnreadIndicatorUpdater/index.js
@@ -1,14 +1,15 @@
-import _ from 'underscore';
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import _ from 'underscore';
+import * as ReportUtils from '@libs/ReportUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import updateUnread from './updateUnread/index';
-import * as ReportUtils from '../ReportUtils';
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
waitForCollectionCallback: true,
callback: (reportsFromOnyx) => {
- const unreadReports = _.filter(reportsFromOnyx, ReportUtils.isUnread);
+ const unreadReports = _.filter(reportsFromOnyx, (report) => ReportUtils.isUnread(report) && report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN);
updateUnread(_.size(unreadReports));
},
});
diff --git a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js
index 4c829239ef14..56aa7f02509d 100644
--- a/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js
+++ b/src/libs/UnreadIndicatorUpdater/updateUnread/index.website.js
@@ -1,7 +1,7 @@
/**
* Web browsers have a tab title and favicon which can be updated to show there are unread comments
*/
-import CONFIG from '../../../CONFIG';
+import CONFIG from '@src/CONFIG';
let unreadTotalCount = 0;
/**
diff --git a/src/libs/UserUtils.ts b/src/libs/UserUtils.ts
index 15bf3c0f1029..f7883609f625 100644
--- a/src/libs/UserUtils.ts
+++ b/src/libs/UserUtils.ts
@@ -1,10 +1,10 @@
import {SvgProps} from 'react-native-svg';
import {ValueOf} from 'type-fest';
-import CONST from '../CONST';
+import * as defaultAvatars from '@components/Icon/DefaultAvatars';
+import {ConciergeAvatar, FallbackAvatar} from '@components/Icon/Expensicons';
+import CONST from '@src/CONST';
+import Login from '@src/types/onyx/Login';
import hashCode from './hashCode';
-import {ConciergeAvatar, FallbackAvatar} from '../components/Icon/Expensicons';
-import * as defaultAvatars from '../components/Icon/DefaultAvatars';
-import Login from '../types/onyx/Login';
type AvatarRange = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24;
diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts
index b94c240b6e92..5947d45a6f76 100644
--- a/src/libs/ValidationUtils.ts
+++ b/src/libs/ValidationUtils.ts
@@ -1,14 +1,14 @@
-import {subYears, addYears, startOfDay, endOfMonth, parse, isAfter, isBefore, isValid, isWithinInterval, isSameDay, format} from 'date-fns';
-import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
import {parsePhoneNumber} from 'awesome-phonenumber';
+import {addYears, endOfMonth, format, isAfter, isBefore, isSameDay, isValid, isWithinInterval, parse, startOfDay, subYears} from 'date-fns';
+import {URL_REGEX_WITH_REQUIRED_PROTOCOL} from 'expensify-common/lib/Url';
import isDate from 'lodash/isDate';
import isEmpty from 'lodash/isEmpty';
import isObject from 'lodash/isObject';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
+import {Report} from '@src/types/onyx';
+import * as OnyxCommon from '@src/types/onyx/OnyxCommon';
import * as CardUtils from './CardUtils';
import * as LoginUtils from './LoginUtils';
-import {Report} from '../types/onyx';
-import * as OnyxCommon from '../types/onyx/OnyxCommon';
/**
* Implements the Luhn Algorithm, a checksum formula used to validate credit card
diff --git a/src/libs/Visibility/index.native.ts b/src/libs/Visibility/index.native.ts
index 695df3651da7..42bd56531207 100644
--- a/src/libs/Visibility/index.native.ts
+++ b/src/libs/Visibility/index.native.ts
@@ -1,6 +1,5 @@
// Mobile apps do not require this check for visibility as
// they do not use the Notification lib.
-
import {AppState} from 'react-native';
import {HasFocus, IsVisible, OnVisibilityChange} from './types';
diff --git a/src/libs/__mocks__/Permissions.ts b/src/libs/__mocks__/Permissions.ts
index 66ef64bbb994..e95d13f52803 100644
--- a/src/libs/__mocks__/Permissions.ts
+++ b/src/libs/__mocks__/Permissions.ts
@@ -1,5 +1,5 @@
-import CONST from '../../CONST';
-import Beta from '../../types/onyx/Beta';
+import CONST from '@src/CONST';
+import Beta from '@src/types/onyx/Beta';
/**
* This module is mocked in tests because all the permission methods call canUseAllBetas() and that will
diff --git a/src/libs/actions/ActiveClients.ts b/src/libs/actions/ActiveClients.ts
index 45fcff402f49..e59fdc14410e 100644
--- a/src/libs/actions/ActiveClients.ts
+++ b/src/libs/actions/ActiveClients.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
function setActiveClients(activeClients: string[]): Promise {
return Onyx.set(ONYXKEYS.ACTIVE_CLIENTS, activeClients);
diff --git a/src/libs/actions/App.js b/src/libs/actions/App.js
index 75520d483f98..884dddf0eb0a 100644
--- a/src/libs/actions/App.js
+++ b/src/libs/actions/App.js
@@ -1,25 +1,25 @@
// Do not remove this import until moment package is fully removed.
// Issue - https://github.com/Expensify/App/issues/26719
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
import 'moment/locale/es';
import {AppState} from 'react-native';
import Onyx from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
import _ from 'underscore';
-import * as API from '../API';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import Log from '../Log';
-import Performance from '../Performance';
+import * as API from '@libs/API';
+import * as Browser from '@libs/Browser';
+import Log from '@libs/Log';
+import getCurrentUrl from '@libs/Navigation/currentUrl';
+import Navigation from '@libs/Navigation/Navigation';
+import Performance from '@libs/Performance';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as SessionUtils from '@libs/SessionUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import * as Policy from './Policy';
-import Navigation from '../Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import * as SessionUtils from '../SessionUtils';
-import getCurrentUrl from '../Navigation/currentUrl';
import * as Session from './Session';
-import * as ReportActionsUtils from '../ReportActionsUtils';
import Timing from './Timing';
-import * as Browser from '../Browser';
let currentUserAccountID;
let currentUserEmail;
@@ -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/AppUpdate.ts b/src/libs/actions/AppUpdate.ts
index f0e3c1c3da20..29ee2a4547ab 100644
--- a/src/libs/actions/AppUpdate.ts
+++ b/src/libs/actions/AppUpdate.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
function triggerUpdateAvailable() {
Onyx.set(ONYXKEYS.UPDATE_AVAILABLE, true);
diff --git a/src/libs/actions/BankAccounts.ts b/src/libs/actions/BankAccounts.ts
index cc755f10dfc6..8d0c59ab8d60 100644
--- a/src/libs/actions/BankAccounts.ts
+++ b/src/libs/actions/BankAccounts.ts
@@ -1,16 +1,16 @@
import Onyx from 'react-native-onyx';
-import CONST from '../../CONST';
-import * as API from '../API';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as ErrorUtils from '../ErrorUtils';
-import * as PlaidDataProps from '../../pages/ReimbursementAccount/plaidDataPropTypes';
-import Navigation from '../Navigation/Navigation';
-import ROUTES from '../../ROUTES';
+import * as API from '@libs/API';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PlaidDataProps from '@pages/ReimbursementAccount/plaidDataPropTypes';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import type PlaidBankAccount from '@src/types/onyx/PlaidBankAccount';
+import type {BankAccountStep, BankAccountSubStep} from '@src/types/onyx/ReimbursementAccount';
+import type {ACHContractStepProps, BankAccountStepProps, CompanyStepProps, OnfidoData, ReimbursementAccountProps, RequestorStepProps} from '@src/types/onyx/ReimbursementAccountDraft';
+import type {OnyxData} from '@src/types/onyx/Request';
import * as ReimbursementAccount from './ReimbursementAccount';
-import type PlaidBankAccount from '../../types/onyx/PlaidBankAccount';
-import type {ACHContractStepProps, BankAccountStepProps, CompanyStepProps, OnfidoData, ReimbursementAccountProps, RequestorStepProps} from '../../types/onyx/ReimbursementAccountDraft';
-import type {OnyxData} from '../../types/onyx/Request';
-import type {BankAccountStep, BankAccountSubStep} from '../../types/onyx/ReimbursementAccount';
export {
goToWithdrawalAccountSetupStep,
@@ -35,7 +35,7 @@ type ReimbursementAccountSubStep = BankAccountSubStep | '';
function clearPlaid(): Promise {
Onyx.set(ONYXKEYS.PLAID_LINK_TOKEN, '');
-
+ Onyx.set(ONYXKEYS.PLAID_CURRENT_EVENT, null);
return Onyx.set(ONYXKEYS.PLAID_DATA, PlaidDataProps.plaidDataDefaultProps);
}
@@ -43,6 +43,10 @@ function openPlaidView() {
clearPlaid().then(() => ReimbursementAccount.setBankAccountSubStep(CONST.BANK_ACCOUNT.SETUP_TYPE.PLAID));
}
+function setPlaidEvent(eventName: string) {
+ Onyx.set(ONYXKEYS.PLAID_CURRENT_EVENT, eventName);
+}
+
/**
* Open the personal bank account setup flow, with an optional exitReportID to redirect to once the flow is finished.
*/
@@ -433,6 +437,7 @@ export {
clearOnfidoToken,
clearPersonalBankAccount,
clearPlaid,
+ setPlaidEvent,
openPlaidView,
connectBankAccountManually,
connectBankAccountWithPlaid,
diff --git a/src/libs/actions/CanvasSize.js b/src/libs/actions/CanvasSize.js
index 0c4cd88fea70..b313763131b9 100644
--- a/src/libs/actions/CanvasSize.js
+++ b/src/libs/actions/CanvasSize.js
@@ -1,7 +1,7 @@
-import Onyx from 'react-native-onyx';
import canvasSize from 'canvas-size';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as Browser from '../Browser';
+import Onyx from 'react-native-onyx';
+import * as Browser from '@libs/Browser';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Calculate the max area of canvas on this specific platform and save it in onyx
diff --git a/src/libs/actions/Card.js b/src/libs/actions/Card.js
index 92b23e2103ee..126608cf1b47 100644
--- a/src/libs/actions/Card.js
+++ b/src/libs/actions/Card.js
@@ -1,6 +1,7 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
+import * as API from '@libs/API';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* @param {Number} cardID
@@ -146,4 +147,29 @@ function clearCardListErrors(cardID) {
Onyx.merge(ONYXKEYS.CARD_LIST, {[cardID]: {errors: null, isLoading: false}});
}
-export {requestReplacementExpensifyCard, activatePhysicalExpensifyCard, clearCardListErrors, reportVirtualExpensifyCardFraud};
+/**
+ * Makes an API call to get virtual card details (pan, cvv, expiration date, address)
+ * This function purposefully uses `makeRequestWithSideEffects` method. For security reason
+ * card details cannot be persisted in Onyx and have to be asked for each time a user want's to
+ * reveal them.
+ *
+ * @param {String} cardID - virtual card ID
+ *
+ * @returns {Promise} - promise with card details object
+ */
+function revealVirtualCardDetails(cardID) {
+ return new Promise((resolve, reject) => {
+ // eslint-disable-next-line rulesdir/no-api-side-effects-method
+ API.makeRequestWithSideEffects('RevealVirtualCardDetails', {cardID})
+ .then((response) => {
+ if (response.jsonCode !== CONST.JSON_CODE.SUCCESS) {
+ reject();
+ return;
+ }
+ resolve(response);
+ })
+ .catch(reject);
+ });
+}
+
+export {requestReplacementExpensifyCard, activatePhysicalExpensifyCard, clearCardListErrors, reportVirtualExpensifyCardFraud, revealVirtualCardDetails};
diff --git a/src/libs/actions/Chronos.ts b/src/libs/actions/Chronos.ts
index ce821e524722..76308f225fe4 100644
--- a/src/libs/actions/Chronos.ts
+++ b/src/libs/actions/Chronos.ts
@@ -1,8 +1,8 @@
import Onyx, {OnyxUpdate} from 'react-native-onyx';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
-import {ChronosOOOEvent} from '../../types/onyx/OriginalMessage';
+import * as API from '@libs/API';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {ChronosOOOEvent} from '@src/types/onyx/OriginalMessage';
const removeEvent = (reportID: string, reportActionID: string, eventID: string, events: ChronosOOOEvent[]) => {
const optimisticData: OnyxUpdate[] = [
diff --git a/src/libs/actions/CloseAccount.ts b/src/libs/actions/CloseAccount.ts
index 8a8f395277e1..01b115a23518 100644
--- a/src/libs/actions/CloseAccount.ts
+++ b/src/libs/actions/CloseAccount.ts
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Clear CloseAccount error message to hide modal
diff --git a/src/libs/actions/Composer.ts b/src/libs/actions/Composer.ts
index d3f9ef9814a5..edd42fb801f2 100644
--- a/src/libs/actions/Composer.ts
+++ b/src/libs/actions/Composer.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
function setShouldShowComposeInput(shouldShowComposeInput: boolean) {
Onyx.set(ONYXKEYS.SHOULD_SHOW_COMPOSE_INPUT, shouldShowComposeInput);
diff --git a/src/libs/actions/CurrentDate.ts b/src/libs/actions/CurrentDate.ts
index b19a3430e96f..4a382156012b 100644
--- a/src/libs/actions/CurrentDate.ts
+++ b/src/libs/actions/CurrentDate.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
function setCurrentDate(currentDate: string) {
Onyx.set(ONYXKEYS.CURRENT_DATE, currentDate);
diff --git a/src/libs/actions/DemoActions.js b/src/libs/actions/DemoActions.js
index e7ce02d2796b..245e475e7ca9 100644
--- a/src/libs/actions/DemoActions.js
+++ b/src/libs/actions/DemoActions.js
@@ -1,11 +1,11 @@
+import lodashGet from 'lodash/get';
import Config from 'react-native-config';
import Onyx from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import * as API from '../API';
-import * as ReportUtils from '../ReportUtils';
-import Navigation from '../Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import ONYXKEYS from '../../ONYXKEYS';
+import * as API from '@libs/API';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
let currentUserEmail;
Onyx.connect({
diff --git a/src/libs/actions/Device/generateDeviceID/index.android.js b/src/libs/actions/Device/generateDeviceID/index.android.js
index f61b860bda7d..41fc946839b7 100644
--- a/src/libs/actions/Device/generateDeviceID/index.android.js
+++ b/src/libs/actions/Device/generateDeviceID/index.android.js
@@ -1,5 +1,5 @@
-import DeviceInfo from 'react-native-device-info';
import Str from 'expensify-common/lib/str';
+import DeviceInfo from 'react-native-device-info';
const deviceID = DeviceInfo.getDeviceId();
const uniqueID = Str.guid(deviceID);
diff --git a/src/libs/actions/Device/index.js b/src/libs/actions/Device/index.js
index 8f548b75bd93..8394bf226b12 100644
--- a/src/libs/actions/Device/index.js
+++ b/src/libs/actions/Device/index.js
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import Log from '../../Log';
+import Log from '@libs/Log';
+import ONYXKEYS from '@src/ONYXKEYS';
import generateDeviceID from './generateDeviceID';
import getDeviceInfo from './getDeviceInfo';
diff --git a/src/libs/actions/Download.ts b/src/libs/actions/Download.ts
index 06b97d735d39..6eb3b1f05b4b 100644
--- a/src/libs/actions/Download.ts
+++ b/src/libs/actions/Download.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Set whether an attachment is being downloaded so that a spinner can be shown.
diff --git a/src/libs/actions/EmojiPickerAction.ts b/src/libs/actions/EmojiPickerAction.ts
index edf82eb46da3..07b00a508dad 100644
--- a/src/libs/actions/EmojiPickerAction.ts
+++ b/src/libs/actions/EmojiPickerAction.ts
@@ -1,7 +1,7 @@
-import {ValueOf} from 'type-fest';
import React from 'react';
import {View} from 'react-native';
-import CONST from '../../CONST';
+import {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
type AnchorOrigin = {
horizontal: ValueOf;
diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js
index 94711f098152..77ab246506ce 100644
--- a/src/libs/actions/IOU.js
+++ b/src/libs/actions/IOU.js
@@ -1,29 +1,29 @@
-import Onyx from 'react-native-onyx';
-import _ from 'underscore';
+import {format} from 'date-fns';
+import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import lodashHas from 'lodash/has';
-import Str from 'expensify-common/lib/str';
-import {format} from 'date-fns';
-import CONST from '../../CONST';
-import ROUTES from '../../ROUTES';
-import ONYXKEYS from '../../ONYXKEYS';
-import Navigation from '../Navigation/Navigation';
-import * as Localize from '../Localize';
-import * as API from '../API';
-import * as ReportUtils from '../ReportUtils';
-import * as CurrencyUtils from '../CurrencyUtils';
-import * as ReportActionsUtils from '../ReportActionsUtils';
-import * as IOUUtils from '../IOUUtils';
-import * as OptionsListUtils from '../OptionsListUtils';
-import DateUtils from '../DateUtils';
-import * as TransactionUtils from '../TransactionUtils';
-import * as ErrorUtils from '../ErrorUtils';
-import * as UserUtils from '../UserUtils';
-import * as Report from './Report';
-import * as NumberUtils from '../NumberUtils';
-import ReceiptGeneric from '../../../assets/images/receipt-generic.png';
-import * as LocalePhoneNumber from '../LocalePhoneNumber';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import ReceiptGeneric from '@assets/images/receipt-generic.png';
+import * as API from '@libs/API';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import DateUtils from '@libs/DateUtils';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import * as IOUUtils from '@libs/IOUUtils';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import * as Localize from '@libs/Localize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as NumberUtils from '@libs/NumberUtils';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import * as UserUtils from '@libs/UserUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import * as Policy from './Policy';
+import * as Report from './Report';
let allPersonalDetails;
Onyx.connect({
@@ -137,6 +137,7 @@ function resetMoneyRequestInfo(id = '') {
receiptFilename: '',
transactionID: '',
billable: null,
+ isSplitRequest: false,
});
}
@@ -525,8 +526,9 @@ function getMoneyRequestInformation(
// 3. IOU action for the iouReport
// 4. REPORTPREVIEW action for the chatReport
// Note: The CREATED action for the IOU report must be optimistically generated before the IOU action so there's no chance that it appears after the IOU action in the chat
+ const currentTime = DateUtils.getDBTime();
const optimisticCreatedActionForChat = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail);
- const optimisticCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail);
+ const optimisticCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(payeeEmail, DateUtils.subtractMillisecondsFromDateTime(currentTime, 1));
const iouAction = ReportUtils.buildOptimisticIOUReportAction(
CONST.IOU.REPORT_ACTION_TYPE.CREATE,
amount,
@@ -539,6 +541,8 @@ function getMoneyRequestInformation(
false,
false,
receiptObject,
+ false,
+ currentTime,
);
let reportPreviewAction = isNewIOUReport ? null : ReportActionsUtils.getReportPreviewAction(chatReport.reportID, iouReport.reportID);
@@ -1122,8 +1126,9 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
// 3. IOU action for the iouReport
// 4. REPORTPREVIEW action for the chatReport
// Note: The CREATED action for the IOU report must be optimistically generated before the IOU action so there's no chance that it appears after the IOU action in the chat
+ const currentTime = DateUtils.getDBTime();
const oneOnOneCreatedActionForChat = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit);
- const oneOnOneCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit);
+ const oneOnOneCreatedActionForIOU = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit, DateUtils.subtractMillisecondsFromDateTime(currentTime, 1));
const oneOnOneIOUAction = ReportUtils.buildOptimisticIOUReportAction(
CONST.IOU.REPORT_ACTION_TYPE.CREATE,
splitAmount,
@@ -1133,6 +1138,11 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
oneOnOneTransaction.transactionID,
'',
oneOnOneIOUReport.reportID,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ currentTime,
);
// Add optimistic personal details for new participants
@@ -1809,6 +1819,8 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC
optimisticPolicyRecentlyUsedTags[tagListName] = [transactionChanges.tag, ...uniquePolicyRecentlyUsedTags];
}
+ const isScanning = TransactionUtils.hasReceipt(updatedTransaction) && TransactionUtils.isReceiptBeingScanned(updatedTransaction);
+
// STEP 4: Compose the optimistic data
const currentTime = DateUtils.getDBTime();
const optimisticData = [
@@ -1842,6 +1854,28 @@ function editMoneyRequest(transactionID, transactionThreadReportID, transactionC
lastVisibleActionCreated: currentTime,
},
},
+ ...(!isScanning
+ ? [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.reportID}`,
+ value: {
+ [transactionThread.parentReportActionID]: {
+ whisperedToAccountIDs: [],
+ },
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport.parentReportID}`,
+ value: {
+ [iouReport.parentReportActionID]: {
+ whisperedToAccountIDs: [],
+ },
+ },
+ },
+ ]
+ : []),
];
if (!_.isEmpty(optimisticPolicyRecentlyUsedTags)) {
@@ -2246,7 +2280,7 @@ function getSendMoneyParams(report, amount, currency, comment, paymentMethodType
},
};
const optimisticChatReportActionsData = {
- onyxMethod: Onyx.METHOD.SET,
+ onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport.reportID}`,
value: {
[reportPreviewAction.reportActionID]: reportPreviewAction,
@@ -2830,9 +2864,10 @@ function setMoneyRequestBillable(billable) {
/**
* @param {Object[]} participants
+ * @param {Boolean} isSplitRequest
*/
-function setMoneyRequestParticipants(participants) {
- Onyx.merge(ONYXKEYS.IOU, {participants});
+function setMoneyRequestParticipants(participants, isSplitRequest) {
+ Onyx.merge(ONYXKEYS.IOU, {participants, isSplitRequest});
}
/**
diff --git a/src/libs/actions/InputFocus/index.desktop.ts b/src/libs/actions/InputFocus/index.desktop.ts
index b6cf1aba6138..86a562f0531e 100644
--- a/src/libs/actions/InputFocus/index.desktop.ts
+++ b/src/libs/actions/InputFocus/index.desktop.ts
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import ReportActionComposeFocusManager from '../../ReportActionComposeFocusManager';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import ONYXKEYS from '@src/ONYXKEYS';
function inputFocusChange(focus: boolean) {
Onyx.set(ONYXKEYS.INPUT_FOCUSED, focus);
diff --git a/src/libs/actions/InputFocus/index.website.ts b/src/libs/actions/InputFocus/index.website.ts
index 7c044b169a03..8e41e06d7401 100644
--- a/src/libs/actions/InputFocus/index.website.ts
+++ b/src/libs/actions/InputFocus/index.website.ts
@@ -1,7 +1,7 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as Browser from '../../Browser';
-import ReportActionComposeFocusManager from '../../ReportActionComposeFocusManager';
+import * as Browser from '@libs/Browser';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import ONYXKEYS from '@src/ONYXKEYS';
function inputFocusChange(focus: boolean) {
Onyx.set(ONYXKEYS.INPUT_FOCUSED, focus);
diff --git a/src/libs/actions/Link.js b/src/libs/actions/Link.js
index 06705182a626..0a50bb62ddc8 100644
--- a/src/libs/actions/Link.js
+++ b/src/libs/actions/Link.js
@@ -1,11 +1,11 @@
-import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import ONYXKEYS from '../../ONYXKEYS';
-import asyncOpenURL from '../asyncOpenURL';
-import * as API from '../API';
-import * as Environment from '../Environment/Environment';
-import * as Url from '../Url';
+import * as API from '@libs/API';
+import asyncOpenURL from '@libs/asyncOpenURL';
+import * as Environment from '@libs/Environment/Environment';
+import * as Url from '@libs/Url';
+import ONYXKEYS from '@src/ONYXKEYS';
let isNetworkOffline = false;
Onyx.connect({
diff --git a/src/libs/actions/MapboxToken.js b/src/libs/actions/MapboxToken.ts
similarity index 82%
rename from src/libs/actions/MapboxToken.js
rename to src/libs/actions/MapboxToken.ts
index 1d4e21ab66ee..4596e82a9354 100644
--- a/src/libs/actions/MapboxToken.js
+++ b/src/libs/actions/MapboxToken.ts
@@ -1,26 +1,25 @@
-import _ from 'underscore';
import {isAfter} from 'date-fns';
+import {AppState, NativeEventSubscription} from 'react-native';
import Onyx from 'react-native-onyx';
-import {AppState} from 'react-native';
-import lodashGet from 'lodash/get';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
-import CONST from '../../CONST';
-import * as ActiveClientManager from '../ActiveClientManager';
-
-let authToken;
+import * as ActiveClientManager from '@libs/ActiveClientManager';
+import * as API from '@libs/API';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {MapboxAccessToken, Network} from '@src/types/onyx';
+
+let authToken: string | null;
Onyx.connect({
key: ONYXKEYS.SESSION,
- callback: (val) => {
- authToken = lodashGet(val, 'authToken', null);
+ callback: (value) => {
+ authToken = value?.authToken ?? null;
},
});
-let connectionIDForToken;
-let connectionIDForNetwork;
-let appStateSubscription;
-let currentToken;
-let refreshTimeoutID;
+let connectionIDForToken: number | null;
+let connectionIDForNetwork: number | null;
+let appStateSubscription: NativeEventSubscription | null;
+let currentToken: MapboxAccessToken | null;
+let refreshTimeoutID: NodeJS.Timeout | undefined;
let isCurrentlyFetchingToken = false;
const REFRESH_INTERVAL = 1000 * 60 * 25;
@@ -38,11 +37,11 @@ const setExpirationTimer = () => {
return;
}
console.debug(`[MapboxToken] Fetching a new token after waiting ${REFRESH_INTERVAL / 1000 / 60} minutes`);
- API.read('GetMapboxAccessToken');
+ API.read('GetMapboxAccessToken', {}, {});
}, REFRESH_INTERVAL);
};
-const hasTokenExpired = () => isAfter(new Date(), new Date(currentToken.expiration));
+const hasTokenExpired = () => isAfter(new Date(), new Date(currentToken?.expiration ?? ''));
const clearToken = () => {
console.debug('[MapboxToken] Deleting the token stored in Onyx');
@@ -51,7 +50,7 @@ const clearToken = () => {
};
const fetchToken = () => {
- API.read('GetMapboxAccessToken');
+ API.read('GetMapboxAccessToken', {}, {});
isCurrentlyFetchingToken = true;
};
@@ -64,12 +63,6 @@ const init = () => {
// When the token changes in Onyx, the expiration needs to be checked so a new token can be retrieved.
connectionIDForToken = Onyx.connect({
key: ONYXKEYS.MAPBOX_ACCESS_TOKEN,
- /**
- * @param {Object} token
- * @param {String} token.token
- * @param {String} token.expiration
- * @param {String[]} [token.errors]
- */
callback: (token) => {
// Only the leader should be in charge of the mapbox token, or else when you have multiple tabs open, the Onyx connection fires multiple times
// and it sets up duplicate refresh timers. This would be a big waste of tokens.
@@ -86,7 +79,7 @@ const init = () => {
// If the token is falsy or an empty object, the token needs to be retrieved from the API.
// The API sets a token in Onyx with a 30 minute expiration.
- if (_.isEmpty(token)) {
+ if (Object.keys(token ?? {}).length === 0) {
fetchToken();
return;
}
@@ -122,21 +115,21 @@ const init = () => {
}
if (!connectionIDForNetwork) {
- let network;
+ let network: Network | null;
connectionIDForNetwork = Onyx.connect({
key: ONYXKEYS.NETWORK,
- callback: (val) => {
+ callback: (value) => {
// When the network reconnects, check if the token has expired. If it has, then clearing the token will
// trigger the fetch of a new one
- if (network && network.isOffline && val && !val.isOffline) {
- if (_.isEmpty(currentToken)) {
+ if (network && network.isOffline && value && !value.isOffline) {
+ if (Object.keys(currentToken ?? {}).length === 0) {
fetchToken();
} else if (!isCurrentlyFetchingToken && hasTokenExpired()) {
console.debug('[MapboxToken] Token is expired after network came online');
clearToken();
}
}
- network = val;
+ network = value;
},
});
}
diff --git a/src/libs/actions/MemoryOnlyKeys/MemoryOnlyKeys.js b/src/libs/actions/MemoryOnlyKeys/MemoryOnlyKeys.js
index d46222189804..028bce225909 100644
--- a/src/libs/actions/MemoryOnlyKeys/MemoryOnlyKeys.js
+++ b/src/libs/actions/MemoryOnlyKeys/MemoryOnlyKeys.js
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import Log from '../../Log';
+import Log from '@libs/Log';
+import ONYXKEYS from '@src/ONYXKEYS';
const memoryOnlyKeys = [ONYXKEYS.COLLECTION.REPORT, ONYXKEYS.COLLECTION.POLICY, ONYXKEYS.PERSONAL_DETAILS_LIST];
diff --git a/src/libs/actions/MemoryOnlyKeys/exposeGlobalMemoryOnlyKeysMethods/index.js b/src/libs/actions/MemoryOnlyKeys/exposeGlobalMemoryOnlyKeysMethods/index.js
index fa62268753db..1d039c8980a9 100644
--- a/src/libs/actions/MemoryOnlyKeys/exposeGlobalMemoryOnlyKeysMethods/index.js
+++ b/src/libs/actions/MemoryOnlyKeys/exposeGlobalMemoryOnlyKeysMethods/index.js
@@ -1,4 +1,4 @@
-import * as MemoryOnlyKeys from '../MemoryOnlyKeys';
+import * as MemoryOnlyKeys from '@userActions/MemoryOnlyKeys/MemoryOnlyKeys';
const exposeGlobalMemoryOnlyKeysMethods = () => {
window.enableMemoryOnlyKeys = () => {
diff --git a/src/libs/actions/Modal.ts b/src/libs/actions/Modal.ts
index ff09731f59a7..5114d5c1f42f 100644
--- a/src/libs/actions/Modal.ts
+++ b/src/libs/actions/Modal.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
let closeModal: (isNavigating: boolean) => void;
let onModalClose: null | (() => void);
diff --git a/src/libs/actions/Network.ts b/src/libs/actions/Network.ts
index 212e44f6782d..17580c214376 100644
--- a/src/libs/actions/Network.ts
+++ b/src/libs/actions/Network.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
function setIsOffline(isOffline: boolean) {
Onyx.merge(ONYXKEYS.NETWORK, {isOffline});
diff --git a/src/libs/actions/OnyxUpdateManager.js b/src/libs/actions/OnyxUpdateManager.js
index b6318b784439..21cea452295b 100644
--- a/src/libs/actions/OnyxUpdateManager.js
+++ b/src/libs/actions/OnyxUpdateManager.js
@@ -1,11 +1,11 @@
import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import ONYXKEYS from '../../ONYXKEYS';
-import Log from '../Log';
-import * as SequentialQueue from '../Network/SequentialQueue';
+import Log from '@libs/Log';
+import * as SequentialQueue from '@libs/Network/SequentialQueue';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as App from './App';
import * as OnyxUpdates from './OnyxUpdates';
-import CONST from '../../CONST';
// This file is in charge of looking at the updateIDs coming from the server and comparing them to the last updateID that the client has.
// If the client is behind the server, then we need to
diff --git a/src/libs/actions/OnyxUpdates.ts b/src/libs/actions/OnyxUpdates.ts
index 39a20ae9362a..b44b485ac60f 100644
--- a/src/libs/actions/OnyxUpdates.ts
+++ b/src/libs/actions/OnyxUpdates.ts
@@ -1,11 +1,11 @@
import Onyx, {OnyxEntry} from 'react-native-onyx';
import {Merge} from 'type-fest';
-import PusherUtils from '../PusherUtils';
-import ONYXKEYS from '../../ONYXKEYS';
+import PusherUtils from '@libs/PusherUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {OnyxUpdateEvent, OnyxUpdatesFromServer, Request} from '@src/types/onyx';
+import Response from '@src/types/onyx/Response';
import * as QueuedOnyxUpdates from './QueuedOnyxUpdates';
-import CONST from '../../CONST';
-import {OnyxUpdatesFromServer, OnyxUpdateEvent, Request} from '../../types/onyx';
-import Response from '../../types/onyx/Response';
// This key needs to be separate from ONYXKEYS.ONYX_UPDATES_FROM_SERVER so that it can be updated without triggering the callback when the server IDs are updated. If that
// callback were triggered it would lead to duplicate processing of server updates.
diff --git a/src/libs/actions/PaymentMethods.ts b/src/libs/actions/PaymentMethods.ts
index fe1b5ebe10e9..dc5b7b83aa8e 100644
--- a/src/libs/actions/PaymentMethods.ts
+++ b/src/libs/actions/PaymentMethods.ts
@@ -1,14 +1,14 @@
import {createRef} from 'react';
import Onyx, {OnyxUpdate} from 'react-native-onyx';
import {ValueOf} from 'type-fest';
-import ONYXKEYS, {OnyxValues} from '../../ONYXKEYS';
-import * as API from '../API';
-import CONST from '../../CONST';
-import Navigation from '../Navigation/Navigation';
-import * as CardUtils from '../CardUtils';
-import ROUTES from '../../ROUTES';
-import {FilterMethodPaymentType} from '../../types/onyx/WalletTransfer';
-import PaymentMethod from '../../types/onyx/PaymentMethod';
+import * as API from '@libs/API';
+import * as CardUtils from '@libs/CardUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import CONST from '@src/CONST';
+import ONYXKEYS, {OnyxValues} from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import PaymentMethod from '@src/types/onyx/PaymentMethod';
+import {FilterMethodPaymentType} from '@src/types/onyx/WalletTransfer';
type KYCWallRef = {
continue?: () => void;
diff --git a/src/libs/actions/PersistedRequests.ts b/src/libs/actions/PersistedRequests.ts
index d9f4ed020109..c35de9ee94c4 100644
--- a/src/libs/actions/PersistedRequests.ts
+++ b/src/libs/actions/PersistedRequests.ts
@@ -1,7 +1,7 @@
-import Onyx from 'react-native-onyx';
import isEqual from 'lodash/isEqual';
-import ONYXKEYS from '../../ONYXKEYS';
-import {Request} from '../../types/onyx';
+import Onyx from 'react-native-onyx';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {Request} from '@src/types/onyx';
let persistedRequests: Request[] = [];
diff --git a/src/libs/actions/PersonalDetails.js b/src/libs/actions/PersonalDetails.js
index 69cf05b89b34..351943ca1f29 100644
--- a/src/libs/actions/PersonalDetails.js
+++ b/src/libs/actions/PersonalDetails.js
@@ -1,14 +1,14 @@
+import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import Onyx from 'react-native-onyx';
-import Str from 'expensify-common/lib/str';
import _ from 'underscore';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import * as API from '../API';
-import * as UserUtils from '../UserUtils';
-import * as LocalePhoneNumber from '../LocalePhoneNumber';
-import ROUTES from '../../ROUTES';
-import Navigation from '../Navigation/Navigation';
+import * as API from '@libs/API';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import Navigation from '@libs/Navigation/Navigation';
+import * as UserUtils from '@libs/UserUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
let currentUserEmail = '';
let currentUserAccountID;
diff --git a/src/libs/actions/Plaid.ts b/src/libs/actions/Plaid.ts
index 410a8c57d176..ab828eefeece 100644
--- a/src/libs/actions/Plaid.ts
+++ b/src/libs/actions/Plaid.ts
@@ -1,8 +1,8 @@
import Onyx from 'react-native-onyx';
-import getPlaidLinkTokenParameters from '../getPlaidLinkTokenParameters';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
-import * as PlaidDataProps from '../../pages/ReimbursementAccount/plaidDataPropTypes';
+import * as API from '@libs/API';
+import getPlaidLinkTokenParameters from '@libs/getPlaidLinkTokenParameters';
+import * as PlaidDataProps from '@pages/ReimbursementAccount/plaidDataPropTypes';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Gets the Plaid Link token used to initialize the Plaid SDK
diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js
index 89324dd35485..8060e737bd22 100644
--- a/src/libs/actions/Policy.js
+++ b/src/libs/actions/Policy.js
@@ -1,19 +1,19 @@
-import _ from 'underscore';
-import Onyx from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import lodashUnion from 'lodash/union';
import {PUBLIC_DOMAINS} from 'expensify-common/lib/CONST';
import Str from 'expensify-common/lib/str';
import {escapeRegExp} from 'lodash';
-import * as API from '../API';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import * as NumberUtils from '../NumberUtils';
-import * as OptionsListUtils from '../OptionsListUtils';
-import * as ErrorUtils from '../ErrorUtils';
-import * as ReportUtils from '../ReportUtils';
-import * as PersonalDetailsUtils from '../PersonalDetailsUtils';
-import Log from '../Log';
+import lodashGet from 'lodash/get';
+import lodashUnion from 'lodash/union';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import * as API from '@libs/API';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Log from '@libs/Log';
+import * as NumberUtils from '@libs/NumberUtils';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const allPolicies = {};
Onyx.connect({
@@ -33,6 +33,7 @@ Onyx.connect({
_.each(policyReports, ({reportID}) => {
cleanUpMergeQueries[`${ONYXKEYS.COLLECTION.REPORT}${reportID}`] = {hasDraft: false};
cleanUpSetQueries[`${ONYXKEYS.COLLECTION.REPORT_DRAFT_COMMENT}${reportID}`] = null;
+ cleanUpSetQueries[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${reportID}`] = null;
});
Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, cleanUpMergeQueries);
Onyx.multiSet(cleanUpSetQueries);
@@ -44,6 +45,13 @@ Onyx.connect({
},
});
+let allPolicyMembers;
+Onyx.connect({
+ key: ONYXKEYS.COLLECTION.POLICY_MEMBERS,
+ waitForCollectionCallback: true,
+ callback: (val) => (allPolicyMembers = val),
+});
+
let lastAccessedWorkspacePolicyID = null;
Onyx.connect({
key: ONYXKEYS.LAST_ACCESSED_WORKSPACE_POLICY_ID,
@@ -116,6 +124,12 @@ function deleteWorkspace(policyID, reports, policyName) {
},
})),
+ ..._.map(reports, ({reportID}) => ({
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${reportID}`,
+ value: null,
+ })),
+
// Add closed actions to all chat reports linked to this policy
..._.map(reports, ({reportID, ownerAccountID}) => {
// Announce & admin chats have FAKE owners, but workspace chats w/ users do have owners.
@@ -162,7 +176,7 @@ function deleteWorkspace(policyID, reports, policyName) {
/**
* Is the user an admin of a free policy (aka workspace)?
*
- * @param {Array} policies
+ * @param {Record} [policies]
* @returns {Boolean}
*/
function isAdminOfFreePolicy(policies) {
@@ -242,6 +256,27 @@ function removeMembers(accountIDs, policyID) {
})),
];
+ // If the policy has primaryLoginsInvited, then it displays informative messages on the members page about which primary logins were added by secondary logins.
+ // If we delete all these logins then we should clear the informative messages since they are no longer relevant.
+ if (!_.isEmpty(policy.primaryLoginsInvited)) {
+ // Take the current policy members and remove them optimistically
+ const policyMemberAccountIDs = _.map(allPolicyMembers[`${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`], (value, key) => Number(key));
+ const remainingMemberAccountIDs = _.difference(policyMemberAccountIDs, accountIDs);
+ const remainingLogins = PersonalDetailsUtils.getLoginsByAccountIDs(remainingMemberAccountIDs);
+ const invitedPrimaryToSecondaryLogins = _.invert(policy.primaryLoginsInvited);
+
+ // Then, if no remaining members exist that were invited by a secondary login, clear the informative messages
+ if (!_.some(remainingLogins, (remainingLogin) => Boolean(invitedPrimaryToSecondaryLogins[remainingLogin]))) {
+ optimisticData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ value: {
+ primaryLoginsInvited: null,
+ },
+ });
+ }
+ }
+
const successData = [
{
onyxMethod: Onyx.METHOD.MERGE,
@@ -365,7 +400,7 @@ function createPolicyExpenseChats(policyID, invitedEmailsToAccountIDs) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${optimisticReport.reportID}`,
value: {
- isLoadingReportActions: false,
+ isLoadingInitialReportActions: false,
},
});
});
@@ -583,6 +618,9 @@ function clearAvatarErrors(policyID) {
* @param {String} currency
*/
function updateGeneralSettings(policyID, name, currency) {
+ const policy = allPolicies[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
+ const distanceUnit = _.find(_.values(policy.customUnits), (unit) => unit.name === CONST.CUSTOM_UNITS.NAME_DISTANCE);
+ const distanceRate = _.find(_.values(distanceUnit ? distanceUnit.rates : {}), (rate) => rate.name === CONST.CUSTOM_UNITS.DEFAULT_RATE);
const optimisticData = [
{
// We use SET because it's faster than merge and avoids a race condition when setting the currency and navigating the user to the Bank account page in confirmCurrencyChangeAndHideModal
@@ -601,6 +639,21 @@ function updateGeneralSettings(policyID, name, currency) {
},
name,
outputCurrency: currency,
+ ...(distanceUnit
+ ? {
+ customUnits: {
+ [distanceUnit.customUnitID]: {
+ ...distanceUnit,
+ rates: {
+ [distanceRate.customUnitRateID]: {
+ ...distanceRate,
+ currency,
+ },
+ },
+ },
+ },
+ }
+ : {}),
},
},
];
@@ -626,6 +679,13 @@ function updateGeneralSettings(policyID, name, currency) {
errorFields: {
generalSettings: ErrorUtils.getMicroSecondOnyxError('workspace.editor.genericFailureMessage'),
},
+ ...(distanceUnit
+ ? {
+ customUnits: {
+ [distanceUnit.customUnitID]: distanceUnit,
+ },
+ }
+ : {}),
},
},
];
@@ -922,8 +982,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 +1002,7 @@ function createDraftInitialWorkspace(policyOwnerEmail = '', policyName = '', pol
outputCurrency: lodashGet(allPersonalDetails, [sessionAccountID, 'localCurrencyCode'], CONST.CURRENCY.USD),
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
customUnits,
+ makeMeAdmin,
},
},
{
@@ -1274,6 +1336,15 @@ function clearErrors(policyID) {
hideWorkspaceAlertMessage(policyID);
}
+/**
+ * Dismiss the informative messages about which policy members were added with primary logins when invited with their secondary login.
+ *
+ * @param {String} policyID
+ */
+function dismissAddedWithPrimaryMessages(policyID) {
+ Onyx.merge(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`, {primaryLoginsInvited: null});
+}
+
/**
* @param {String} policyID
* @param {String} category
@@ -1317,6 +1388,7 @@ export {
removeWorkspace,
setWorkspaceInviteMembersDraft,
clearErrors,
+ dismissAddedWithPrimaryMessages,
openDraftWorkspaceRequest,
buildOptimisticPolicyRecentlyUsedCategories,
createDraftInitialWorkspace,
diff --git a/src/libs/actions/PushNotification.js b/src/libs/actions/PushNotification.js
index b9a75767d8f6..7abbd7b94ba0 100644
--- a/src/libs/actions/PushNotification.js
+++ b/src/libs/actions/PushNotification.js
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
+import * as API from '@libs/API';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as Device from './Device';
let isUserOptedInToPushNotifications = false;
diff --git a/src/libs/actions/ReimbursementAccount/deleteFromBankAccountList.js b/src/libs/actions/ReimbursementAccount/deleteFromBankAccountList.js
index b640d45683ec..6161066c1c69 100644
--- a/src/libs/actions/ReimbursementAccount/deleteFromBankAccountList.js
+++ b/src/libs/actions/ReimbursementAccount/deleteFromBankAccountList.js
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as store from './store';
/**
diff --git a/src/libs/actions/ReimbursementAccount/errors.js b/src/libs/actions/ReimbursementAccount/errors.js
index 54d881cc4516..fd2eaf852bce 100644
--- a/src/libs/actions/ReimbursementAccount/errors.js
+++ b/src/libs/actions/ReimbursementAccount/errors.js
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as ErrorUtils from '../../ErrorUtils';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Set the current fields with errors.
diff --git a/src/libs/actions/ReimbursementAccount/index.js b/src/libs/actions/ReimbursementAccount/index.js
index 68774d0ba8b0..0404115f086b 100644
--- a/src/libs/actions/ReimbursementAccount/index.js
+++ b/src/libs/actions/ReimbursementAccount/index.js
@@ -1,7 +1,7 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import resetFreePlanBankAccount from './resetFreePlanBankAccount';
+import ONYXKEYS from '@src/ONYXKEYS';
import deleteFromBankAccountList from './deleteFromBankAccountList';
+import resetFreePlanBankAccount from './resetFreePlanBankAccount';
export {goToWithdrawalAccountSetupStep, navigateToBankAccountRoute} from './navigation';
export {setBankAccountFormValidationErrors, setPersonalBankAccountFormValidationErrorFields, resetReimbursementAccount, showBankAccountFormValidationError} from './errors';
diff --git a/src/libs/actions/ReimbursementAccount/navigation.js b/src/libs/actions/ReimbursementAccount/navigation.js
index 1b75e6f16a58..ebc1862e9c74 100644
--- a/src/libs/actions/ReimbursementAccount/navigation.js
+++ b/src/libs/actions/ReimbursementAccount/navigation.js
@@ -1,7 +1,7 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import ROUTES from '../../../ROUTES';
-import Navigation from '../../Navigation/Navigation';
+import Navigation from '@libs/Navigation/Navigation';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
/**
* Navigate to a specific step in the VBA flow
diff --git a/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.js b/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.js
index 388010e99569..37122c107359 100644
--- a/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.js
+++ b/src/libs/actions/ReimbursementAccount/resetFreePlanBankAccount.js
@@ -1,9 +1,9 @@
import Onyx from 'react-native-onyx';
-import CONST from '../../../CONST';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as API from '../../API';
-import * as PlaidDataProps from '../../../pages/ReimbursementAccount/plaidDataPropTypes';
-import * as ReimbursementAccountProps from '../../../pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import * as API from '@libs/API';
+import * as PlaidDataProps from '@pages/ReimbursementAccount/plaidDataPropTypes';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Reset user's reimbursement account. This will delete the bank account.
diff --git a/src/libs/actions/ReimbursementAccount/store.js b/src/libs/actions/ReimbursementAccount/store.js
index 422c0ffc43dd..4b8549b60b2e 100644
--- a/src/libs/actions/ReimbursementAccount/store.js
+++ b/src/libs/actions/ReimbursementAccount/store.js
@@ -1,8 +1,8 @@
-import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import ONYXKEYS from '../../../ONYXKEYS';
-import BankAccount from '../../models/BankAccount';
+import BankAccount from '@libs/models/BankAccount';
+import ONYXKEYS from '@src/ONYXKEYS';
/** Reimbursement account actively being set up */
let reimbursementAccountInSetup = {};
diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js
index be9e93c4c867..3f7dc76b174d 100644
--- a/src/libs/actions/Report.js
+++ b/src/libs/actions/Report.js
@@ -1,33 +1,33 @@
-import {InteractionManager} from 'react-native';
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import lodashDebounce from 'lodash/debounce';
+import {format as timezoneFormat, utcToZonedTime} from 'date-fns-tz';
import ExpensiMark from 'expensify-common/lib/ExpensiMark';
-import Onyx from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
-import {format as timezoneFormat, utcToZonedTime} from 'date-fns-tz';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as Pusher from '../Pusher/pusher';
-import LocalNotification from '../Notification/LocalNotification';
-import Navigation from '../Navigation/Navigation';
-import * as ActiveClientManager from '../ActiveClientManager';
-import Visibility from '../Visibility';
-import ROUTES from '../../ROUTES';
-import * as API from '../API';
-import CONFIG from '../../CONFIG';
-import CONST from '../../CONST';
-import Log from '../Log';
-import * as ReportUtils from '../ReportUtils';
-import DateUtils from '../DateUtils';
-import * as ReportActionsUtils from '../ReportActionsUtils';
-import * as CollectionUtils from '../CollectionUtils';
-import * as EmojiUtils from '../EmojiUtils';
-import * as ErrorUtils from '../ErrorUtils';
-import * as UserUtils from '../UserUtils';
-import * as Welcome from './Welcome';
-import * as PersonalDetailsUtils from '../PersonalDetailsUtils';
-import * as Environment from '../Environment/Environment';
+import lodashDebounce from 'lodash/debounce';
+import lodashGet from 'lodash/get';
+import {InteractionManager} from 'react-native';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import * as ActiveClientManager from '@libs/ActiveClientManager';
+import * as API from '@libs/API';
+import * as CollectionUtils from '@libs/CollectionUtils';
+import DateUtils from '@libs/DateUtils';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import * as Environment from '@libs/Environment/Environment';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import LocalNotification from '@libs/Notification/LocalNotification';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import * as Pusher from '@libs/Pusher/pusher';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import Visibility from '@libs/Visibility';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import * as Session from './Session';
+import * as Welcome from './Welcome';
let currentUserAccountID;
Onyx.connect({
@@ -477,8 +477,9 @@ function openReport(reportID, participantLoginList = [], newReportObject = {}, p
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingReportActions: true,
- isLoadingMoreReportActions: false,
+ isLoadingInitialReportActions: true,
+ isLoadingOlderReportActions: false,
+ isLoadingNewerReportActions: false,
},
},
];
@@ -501,7 +502,7 @@ function openReport(reportID, participantLoginList = [], newReportObject = {}, p
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingReportActions: false,
+ isLoadingInitialReportActions: false,
},
},
];
@@ -511,7 +512,7 @@ function openReport(reportID, participantLoginList = [], newReportObject = {}, p
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingReportActions: false,
+ isLoadingInitialReportActions: false,
},
},
];
@@ -737,8 +738,9 @@ function reconnect(reportID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingReportActions: true,
- isLoadingMoreReportActions: false,
+ isLoadingInitialReportActions: true,
+ isLoadingNewerReportActions: false,
+ isLoadingOlderReportActions: false,
},
},
],
@@ -747,7 +749,7 @@ function reconnect(reportID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingReportActions: false,
+ isLoadingInitialReportActions: false,
},
},
],
@@ -756,7 +758,7 @@ function reconnect(reportID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingReportActions: false,
+ isLoadingInitialReportActions: false,
},
},
],
@@ -771,9 +773,55 @@ function reconnect(reportID) {
* @param {String} reportID
* @param {String} reportActionID
*/
-function readOldestAction(reportID, reportActionID) {
+function getOlderActions(reportID, reportActionID) {
+ API.read(
+ 'GetOlderActions',
+ {
+ reportID,
+ reportActionID,
+ },
+ {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
+ value: {
+ isLoadingOlderReportActions: true,
+ },
+ },
+ ],
+ successData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
+ value: {
+ isLoadingOlderReportActions: false,
+ },
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
+ value: {
+ isLoadingOlderReportActions: false,
+ },
+ },
+ ],
+ },
+ );
+}
+
+/**
+ * Gets the newer actions that have not been read yet.
+ * Normally happens when you are not located at the bottom of the list and scroll down on a chat.
+ *
+ * @param {String} reportID
+ * @param {String} reportActionID
+ */
+function getNewerActions(reportID, reportActionID) {
API.read(
- 'ReadOldestAction',
+ 'GetNewerActions',
{
reportID,
reportActionID,
@@ -784,7 +832,7 @@ function readOldestAction(reportID, reportActionID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingMoreReportActions: true,
+ isLoadingNewerReportActions: true,
},
},
],
@@ -793,7 +841,7 @@ function readOldestAction(reportID, reportActionID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingMoreReportActions: false,
+ isLoadingNewerReportActions: false,
},
},
],
@@ -802,7 +850,7 @@ function readOldestAction(reportID, reportActionID) {
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.REPORT_METADATA}${reportID}`,
value: {
- isLoadingMoreReportActions: false,
+ isLoadingNewerReportActions: false,
},
},
],
@@ -1101,14 +1149,17 @@ function deleteReportComment(reportID, reportAction) {
},
];
- // Update optimistic data for parent report action if the report is a child report
- const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(
- originalReportID,
- optimisticReport.lastVisibleActionCreated,
- CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
- );
- if (!_.isEmpty(optimisticParentReportData)) {
- optimisticData.push(optimisticParentReportData);
+ // Update optimistic data for parent report action if the report is a child report and the reportAction has no visible child
+ const childVisibleActionCount = reportAction.childVisibleActionCount || 0;
+ if (childVisibleActionCount === 0) {
+ const optimisticParentReportData = ReportUtils.getOptimisticDataForParentReportAction(
+ originalReportID,
+ optimisticReport.lastVisibleActionCreated,
+ CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
+ );
+ if (!_.isEmpty(optimisticParentReportData)) {
+ optimisticData.push(optimisticParentReportData);
+ }
}
// Check to see if the report action we are deleting is the first comment on a thread report. In this case, we need to trigger
@@ -1291,7 +1342,7 @@ function editReportComment(reportID, originalReportAction, textForNewComment) {
*/
function saveReportActionDraft(reportID, reportAction, draftMessage) {
const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction);
- Onyx.set(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${originalReportID}_${reportAction.reportActionID}`, draftMessage);
+ Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${originalReportID}`, {[reportAction.reportActionID]: draftMessage});
}
/**
@@ -1309,8 +1360,10 @@ function saveReportActionDraftNumberOfLines(reportID, reportActionID, numberOfLi
* @param {String} previousValue
* @param {String} newValue
* @param {boolean} navigate
+ * @param {String} parentReportID
+ * @param {String} parentReportActionID
*/
-function updateNotificationPreference(reportID, previousValue, newValue, navigate) {
+function updateNotificationPreference(reportID, previousValue, newValue, navigate, parentReportID = 0, parentReportActionID = 0) {
if (previousValue === newValue) {
if (navigate) {
Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID));
@@ -1331,12 +1384,68 @@ function updateNotificationPreference(reportID, previousValue, newValue, navigat
value: {notificationPreference: previousValue},
},
];
+ if (parentReportID && parentReportActionID) {
+ optimisticData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`,
+ value: {[parentReportActionID]: {childReportNotificationPreference: newValue}},
+ });
+ failureData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`,
+ value: {[parentReportActionID]: {childReportNotificationPreference: previousValue}},
+ });
+ }
API.write('UpdateReportNotificationPreference', {reportID, notificationPreference: newValue}, {optimisticData, failureData});
if (navigate) {
Navigation.goBack(ROUTES.REPORT_SETTINGS.getRoute(reportID));
}
}
+/**
+ * This will subscribe to an existing thread, or create a new one and then subsribe to it if necessary
+ *
+ * @param {String} childReportID The reportID we are trying to open
+ * @param {Object} parentReportAction the parent comment of a thread
+ * @param {String} parentReportID The reportID of the parent
+ * @param {String} prevNotificationPreference The previous notification preference for the child report
+ *
+ */
+function toggleSubscribeToChildReport(childReportID = '0', parentReportAction = {}, parentReportID = '0', prevNotificationPreference) {
+ if (childReportID !== '0') {
+ openReport(childReportID);
+ const parentReportActionID = lodashGet(parentReportAction, 'reportActionID', '0');
+ if (!prevNotificationPreference || prevNotificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN) {
+ updateNotificationPreference(childReportID, prevNotificationPreference, CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS, false, parentReportID, parentReportActionID);
+ } else {
+ updateNotificationPreference(childReportID, prevNotificationPreference, CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN, false, parentReportID, parentReportActionID);
+ }
+ } else {
+ const participantAccountIDs = _.uniq([currentUserAccountID, Number(parentReportAction.actorAccountID)]);
+ const parentReport = allReports[parentReportID];
+ const newChat = ReportUtils.buildOptimisticChatReport(
+ participantAccountIDs,
+ lodashGet(parentReportAction, ['message', 0, 'text']),
+ lodashGet(parentReport, 'chatType', ''),
+ lodashGet(parentReport, 'policyID', CONST.POLICY.OWNER_EMAIL_FAKE),
+ CONST.POLICY.OWNER_ACCOUNT_ID_FAKE,
+ false,
+ '',
+ undefined,
+ undefined,
+ CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS,
+ parentReportAction.reportActionID,
+ parentReportID,
+ );
+
+ const participantLogins = PersonalDetailsUtils.getLoginsByAccountIDs(newChat.participantAccountIDs);
+ openReport(newChat.reportID, participantLogins, newChat, parentReportAction.reportActionID);
+ const notificationPreference =
+ prevNotificationPreference === CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
+ updateNotificationPreference(newChat.reportID, prevNotificationPreference, notificationPreference, false, parentReportID, parentReportAction.reportActionID);
+ }
+}
+
/**
* @param {String} reportID
* @param {String} previousValue
@@ -2311,7 +2420,7 @@ function clearPrivateNotesError(reportID, accountID) {
}
function getDraftPrivateNote(reportID) {
- return draftNoteMap[reportID];
+ return draftNoteMap[reportID] || '';
}
/**
@@ -2411,12 +2520,12 @@ export {
expandURLPreview,
markCommentAsUnread,
readNewestAction,
- readOldestAction,
openReport,
openReportFromDeepLink,
navigateToAndOpenReport,
navigateToAndOpenReportWithAccountIDs,
navigateToAndOpenChildReport,
+ toggleSubscribeToChildReport,
updatePolicyRoomNameAndNavigate,
clearPolicyRoomNameErrors,
clearIOUError,
@@ -2436,6 +2545,8 @@ export {
getReportPrivateNote,
clearPrivateNotesError,
hasErrorInPrivateNotes,
+ getOlderActions,
+ getNewerActions,
openRoomMembersPage,
savePrivateNotesDraft,
getDraftPrivateNote,
diff --git a/src/libs/actions/ReportActions.ts b/src/libs/actions/ReportActions.ts
index 3faa1dbe3574..b9cea498a3fa 100644
--- a/src/libs/actions/ReportActions.ts
+++ b/src/libs/actions/ReportActions.ts
@@ -1,9 +1,9 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import * as ReportActionUtils from '../ReportActionsUtils';
-import * as ReportUtils from '../ReportUtils';
-import ReportAction from '../../types/onyx/ReportAction';
+import * as ReportActionUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ReportAction from '@src/types/onyx/ReportAction';
function clearReportActionErrors(reportID: string, reportAction: ReportAction) {
const originalReportID = ReportUtils.getOriginalReportID(reportID, reportAction);
diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts
index c03335959e71..74d2f609ab9b 100644
--- a/src/libs/actions/Session/index.ts
+++ b/src/libs/actions/Session/index.ts
@@ -1,30 +1,30 @@
-import Onyx, {OnyxUpdate} from 'react-native-onyx';
-import {Linking} from 'react-native';
-import {ValueOf} from 'type-fest';
import throttle from 'lodash/throttle';
-import {ChannelAuthorizationCallback} from 'pusher-js/with-encryption';
import {ChannelAuthorizationData} from 'pusher-js/types/src/core/auth/options';
+import {ChannelAuthorizationCallback} from 'pusher-js/with-encryption';
+import {Linking} from 'react-native';
+import Onyx, {OnyxUpdate} from 'react-native-onyx';
+import {ValueOf} from 'type-fest';
+import * as API from '@libs/API';
+import * as Authentication from '@libs/Authentication';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import * as NetworkStore from '@libs/Network/NetworkStore';
+import * as Pusher from '@libs/Pusher/pusher';
+import * as ReportUtils from '@libs/ReportUtils';
+import Timers from '@libs/Timers';
+import {hideContextMenu} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
+import * as Device from '@userActions/Device';
+import redirectToSignIn from '@userActions/SignInRedirect';
+import Timing from '@userActions/Timing';
+import * as Welcome from '@userActions/Welcome';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import Credentials from '@src/types/onyx/Credentials';
+import {AutoAuthState} from '@src/types/onyx/Session';
import clearCache from './clearCache';
-import ONYXKEYS from '../../../ONYXKEYS';
-import redirectToSignIn from '../SignInRedirect';
-import CONFIG from '../../../CONFIG';
-import Log from '../../Log';
-import Timing from '../Timing';
-import CONST from '../../../CONST';
-import Timers from '../../Timers';
-import * as Pusher from '../../Pusher/pusher';
-import * as Authentication from '../../Authentication';
-import * as Welcome from '../Welcome';
-import * as API from '../../API';
-import * as NetworkStore from '../../Network/NetworkStore';
-import Navigation from '../../Navigation/Navigation';
-import * as Device from '../Device';
-import ROUTES from '../../../ROUTES';
-import * as ErrorUtils from '../../ErrorUtils';
-import * as ReportUtils from '../../ReportUtils';
-import {hideContextMenu} from '../../../pages/home/report/ContextMenu/ReportActionContextMenu';
-import Credentials from '../../../types/onyx/Credentials';
-import {AutoAuthState} from '../../../types/onyx/Session';
let sessionAuthTokenType: string | null = '';
let sessionAuthToken: string | null = null;
@@ -99,6 +99,9 @@ function signOutAndRedirectToSignIn() {
signOut();
redirectToSignIn();
} else {
+ if (Navigation.isActiveRoute(ROUTES.SIGN_IN_MODAL)) {
+ return;
+ }
Navigation.navigate(ROUTES.SIGN_IN_MODAL);
Linking.getInitialURL().then((url) => {
const reportID = ReportUtils.getReportIDFromLink(url);
diff --git a/src/libs/actions/Session/updateSessionAuthTokens.ts b/src/libs/actions/Session/updateSessionAuthTokens.ts
index 9614face2070..6f90b60ef06d 100644
--- a/src/libs/actions/Session/updateSessionAuthTokens.ts
+++ b/src/libs/actions/Session/updateSessionAuthTokens.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
export default function updateSessionAuthTokens(authToken?: string, encryptedAuthToken?: string) {
Onyx.merge(ONYXKEYS.SESSION, {authToken, encryptedAuthToken});
diff --git a/src/libs/actions/SignInRedirect.ts b/src/libs/actions/SignInRedirect.ts
index 67f5f2d8586f..9ca4e6813567 100644
--- a/src/libs/actions/SignInRedirect.ts
+++ b/src/libs/actions/SignInRedirect.ts
@@ -1,14 +1,14 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS, {OnyxKey} from '../../ONYXKEYS';
-import * as MainQueue from '../Network/MainQueue';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import HttpUtils from '@libs/HttpUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import navigationRef from '@libs/Navigation/navigationRef';
+import * as MainQueue from '@libs/Network/MainQueue';
+import NetworkConnection from '@libs/NetworkConnection';
+import * as SessionUtils from '@libs/SessionUtils';
+import ONYXKEYS, {OnyxKey} from '@src/ONYXKEYS';
+import SCREENS from '@src/SCREENS';
import * as PersistedRequests from './PersistedRequests';
-import NetworkConnection from '../NetworkConnection';
-import HttpUtils from '../HttpUtils';
-import navigationRef from '../Navigation/navigationRef';
-import SCREENS from '../../SCREENS';
-import Navigation from '../Navigation/Navigation';
-import * as ErrorUtils from '../ErrorUtils';
-import * as SessionUtils from '../SessionUtils';
let currentIsOffline: boolean | undefined;
let currentShouldForceOffline: boolean | undefined;
diff --git a/src/libs/actions/Tab.ts b/src/libs/actions/Tab.ts
index 7acd978d6b1a..a210cef36c73 100644
--- a/src/libs/actions/Tab.ts
+++ b/src/libs/actions/Tab.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Sets the selected tab for a given tab ID
diff --git a/src/libs/actions/Task.js b/src/libs/actions/Task.js
index e7b29bb7ea6c..76396b1f31b8 100644
--- a/src/libs/actions/Task.js
+++ b/src/libs/actions/Task.js
@@ -1,19 +1,20 @@
-import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
-import * as ReportUtils from '../ReportUtils';
-import Navigation from '../Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import CONST from '../../CONST';
-import DateUtils from '../DateUtils';
-import * as UserUtils from '../UserUtils';
-import * as ErrorUtils from '../ErrorUtils';
-import * as ReportActionsUtils from '../ReportActionsUtils';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import * as LocalePhoneNumber from '../LocalePhoneNumber';
-import * as Localize from '../Localize';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as API from '@libs/API';
+import DateUtils from '@libs/DateUtils';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import * as Localize from '@libs/Localize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
let currentUserEmail;
let currentUserAccountID;
@@ -355,11 +356,9 @@ function reopenTask(taskReport) {
/**
* @param {object} report
- * @param {Number} ownerAccountID
* @param {Object} editedTask
- * @param {Object} assigneeChatReport - The chat report between you and the assignee
*/
-function editTaskAndNavigate(report, ownerAccountID, {title, description, assignee = '', assigneeAccountID = 0}, assigneeChatReport = null) {
+function editTaskAndNavigate(report, {title, description}) {
// Create the EditedReportAction on the task
const editTaskReportAction = ReportUtils.buildOptimisticEditedTaskReportAction(currentUserEmail);
@@ -369,9 +368,6 @@ function editTaskAndNavigate(report, ownerAccountID, {title, description, assign
// Description can be unset, so we default to an empty string if so
const reportDescription = (!_.isUndefined(description) ? description : lodashGet(report, 'description', '')).trim();
- let assigneeChatReportOnyxData;
- const assigneeChatReportID = assigneeChatReport ? assigneeChatReport.reportID : 0;
-
const optimisticData = [
{
onyxMethod: Onyx.METHOD.MERGE,
@@ -384,12 +380,9 @@ function editTaskAndNavigate(report, ownerAccountID, {title, description, assign
value: {
reportName,
description: reportDescription,
- managerID: assigneeAccountID || report.managerID,
- managerEmail: assignee || report.managerEmail,
pendingFields: {
...(title && {reportName: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
...(description && {description: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
- ...(assigneeAccountID && {managerID: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE}),
},
},
},
@@ -402,7 +395,6 @@ function editTaskAndNavigate(report, ownerAccountID, {title, description, assign
pendingFields: {
...(title && {reportName: null}),
...(description && {description: null}),
- ...(assigneeAccountID && {managerID: null}),
},
},
},
@@ -419,46 +411,17 @@ function editTaskAndNavigate(report, ownerAccountID, {title, description, assign
value: {
reportName: report.reportName,
description: report.description,
- assignee: report.managerEmail,
- assigneeAccountID: report.managerID,
},
},
];
- // If we make a change to the assignee, we want to add a comment to the assignee's chat
- // Check if the assignee actually changed
- if (assigneeAccountID && assigneeAccountID !== report.managerID && assigneeAccountID !== ownerAccountID && assigneeChatReport) {
- assigneeChatReportOnyxData = ReportUtils.getTaskAssigneeChatOnyxData(
- currentUserAccountID,
- assignee,
- assigneeAccountID,
- report.reportID,
- assigneeChatReportID,
- report.parentReportID,
- reportName,
- assigneeChatReport,
- );
- optimisticData.push(...assigneeChatReportOnyxData.optimisticData);
- successData.push(...assigneeChatReportOnyxData.successData);
- failureData.push(...assigneeChatReportOnyxData.failureData);
- }
-
API.write(
'EditTask',
{
taskReportID: report.reportID,
title: reportName,
description: reportDescription,
- assignee: assignee || report.managerEmail,
- assigneeAccountID: assigneeAccountID || report.managerID,
editedTaskReportActionID: editTaskReportAction.reportActionID,
- assigneeChatReportID,
- assigneeChatReportActionID:
- assigneeChatReportOnyxData && assigneeChatReportOnyxData.optimisticAssigneeAddComment
- ? assigneeChatReportOnyxData.optimisticAssigneeAddComment.reportAction.reportActionID
- : 0,
- assigneeChatCreatedReportActionID:
- assigneeChatReportOnyxData && assigneeChatReportOnyxData.optimisticChatCreatedReportAction ? assigneeChatReportOnyxData.optimisticChatCreatedReportAction.reportActionID : 0,
},
{optimisticData, successData, failureData},
);
@@ -708,6 +671,11 @@ function getAssignee(assigneeAccountID, personalDetails) {
* */
function getShareDestination(reportID, reports, personalDetails) {
const report = lodashGet(reports, `report_${reportID}`, {});
+
+ const participantAccountIDs = lodashGet(report, 'participantAccountIDs');
+ const isMultipleParticipant = participantAccountIDs.length > 1;
+ const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs(participantAccountIDs, personalDetails), isMultipleParticipant);
+
let subtitle = '';
if (ReportUtils.isChatReport(report) && ReportUtils.isDM(report) && ReportUtils.hasSingleParticipant(report)) {
const participantAccountID = lodashGet(report, 'participantAccountIDs[0]');
@@ -721,6 +689,8 @@ function getShareDestination(reportID, reports, personalDetails) {
icons: ReportUtils.getIcons(report, personalDetails, Expensicons.FallbackAvatar),
displayName: ReportUtils.getReportName(report),
subtitle,
+ displayNamesWithTooltips,
+ shouldUseFullTitleToDisplay: ReportUtils.shouldUseFullTitleToDisplay(report),
};
}
diff --git a/src/libs/actions/TeachersUnite.js b/src/libs/actions/TeachersUnite.js
index 39b9de8c6478..98b1f82629a4 100644
--- a/src/libs/actions/TeachersUnite.js
+++ b/src/libs/actions/TeachersUnite.js
@@ -1,12 +1,12 @@
-import _ from 'underscore';
-import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
-import Navigation from '../Navigation/Navigation';
-import CONST from '../../CONST';
-import * as ReportUtils from '../ReportUtils';
-import * as OptionsListUtils from '../OptionsListUtils';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import * as API from '@libs/API';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
let sessionEmail = '';
let sessionAccountID = 0;
diff --git a/src/libs/actions/TestTool.ts b/src/libs/actions/TestTool.ts
index 11de9498b7b0..dc7b371bfe12 100644
--- a/src/libs/actions/TestTool.ts
+++ b/src/libs/actions/TestTool.ts
@@ -1,7 +1,7 @@
import throttle from 'lodash/throttle';
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
let isTestToolsModalOpen = false;
Onyx.connect({
diff --git a/src/libs/actions/Timing.ts b/src/libs/actions/Timing.ts
index 13f40bab87c9..0cef2fe4d2b8 100644
--- a/src/libs/actions/Timing.ts
+++ b/src/libs/actions/Timing.ts
@@ -1,8 +1,8 @@
-import getPlatform from '../getPlatform';
-import * as Environment from '../Environment/Environment';
-import Firebase from '../Firebase';
-import * as API from '../API';
-import Log from '../Log';
+import * as API from '@libs/API';
+import * as Environment from '@libs/Environment/Environment';
+import Firebase from '@libs/Firebase';
+import getPlatform from '@libs/getPlatform';
+import Log from '@libs/Log';
type TimestampData = {
startTime: number;
diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts
index 8a7f0f7bd533..a649267c0ae9 100644
--- a/src/libs/actions/Transaction.ts
+++ b/src/libs/actions/Transaction.ts
@@ -1,14 +1,14 @@
-import Onyx from 'react-native-onyx';
-import lodashHas from 'lodash/has';
-import lodashClone from 'lodash/clone';
import {isEqual} from 'lodash';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as CollectionUtils from '../CollectionUtils';
-import * as API from '../API';
-import CONST from '../../CONST';
-import {RecentWaypoint, Transaction} from '../../types/onyx';
-import {WaypointCollection} from '../../types/onyx/Transaction';
-import * as TransactionUtils from '../TransactionUtils';
+import lodashClone from 'lodash/clone';
+import lodashHas from 'lodash/has';
+import Onyx from 'react-native-onyx';
+import * as API from '@libs/API';
+import * as CollectionUtils from '@libs/CollectionUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {RecentWaypoint, Transaction} from '@src/types/onyx';
+import {WaypointCollection} from '@src/types/onyx/Transaction';
let recentWaypoints: RecentWaypoint[] = [];
Onyx.connect({
diff --git a/src/libs/actions/TransactionEdit.js b/src/libs/actions/TransactionEdit.js
index 44b489b72c43..78a271f0f8cd 100644
--- a/src/libs/actions/TransactionEdit.js
+++ b/src/libs/actions/TransactionEdit.js
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Makes a backup copy of a transaction object that can be restored when the user cancels editing a transaction.
diff --git a/src/libs/actions/TwoFactorAuthActions.ts b/src/libs/actions/TwoFactorAuthActions.ts
index 0cec7d3c16c8..ccd4e2baf662 100644
--- a/src/libs/actions/TwoFactorAuthActions.ts
+++ b/src/libs/actions/TwoFactorAuthActions.ts
@@ -1,8 +1,8 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import Navigation from '../Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import {TwoFactorAuthStep} from '../../types/onyx/Account';
+import Navigation from '@libs/Navigation/Navigation';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {TwoFactorAuthStep} from '@src/types/onyx/Account';
/**
* Clear 2FA data if the flow is interrupted without finishing
diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js
index f65c20cd7e5b..f7375a5583a6 100644
--- a/src/libs/actions/User.js
+++ b/src/libs/actions/User.js
@@ -1,22 +1,22 @@
-import _ from 'underscore';
+import {isBefore} from 'date-fns';
import lodashGet from 'lodash/get';
import Onyx from 'react-native-onyx';
-import {isBefore} from 'date-fns';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
-import CONST from '../../CONST';
-import Navigation from '../Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import * as Pusher from '../Pusher/pusher';
+import _ from 'underscore';
+import * as API from '@libs/API';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as SequentialQueue from '@libs/Network/SequentialQueue';
+import * as Pusher from '@libs/Pusher/pusher';
+import PusherUtils from '@libs/PusherUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import * as Link from './Link';
-import * as SequentialQueue from '../Network/SequentialQueue';
-import PusherUtils from '../PusherUtils';
+import * as OnyxUpdates from './OnyxUpdates';
+import * as PersonalDetails from './PersonalDetails';
import * as Report from './Report';
-import * as ReportActionsUtils from '../ReportActionsUtils';
-import * as ErrorUtils from '../ErrorUtils';
import * as Session from './Session';
-import * as PersonalDetails from './PersonalDetails';
-import * as OnyxUpdates from './OnyxUpdates';
import redirectToSignIn from './SignInRedirect';
let currentUserAccountID = '';
diff --git a/src/libs/actions/Wallet.js b/src/libs/actions/Wallet.js
index 9ef4b547d4b4..bfc2a7306434 100644
--- a/src/libs/actions/Wallet.js
+++ b/src/libs/actions/Wallet.js
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as API from '../API';
+import * as API from '@libs/API';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* Fetch and save locally the Onfido SDK token and applicantID
diff --git a/src/libs/actions/Welcome.js b/src/libs/actions/Welcome.ts
similarity index 59%
rename from src/libs/actions/Welcome.js
rename to src/libs/actions/Welcome.ts
index 8e1832edb9a7..7fd7adeafa96 100644
--- a/src/libs/actions/Welcome.js
+++ b/src/libs/actions/Welcome.ts
@@ -1,22 +1,33 @@
-import Onyx from 'react-native-onyx';
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import Navigation from '../Navigation/Navigation';
-import * as ReportUtils from '../ReportUtils';
-import ROUTES from '../../ROUTES';
+import Onyx, {OnyxCollection} from 'react-native-onyx';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
+import OnyxPolicy from '@src/types/onyx/Policy';
+import Report from '@src/types/onyx/Report';
import * as Policy from './Policy';
-import ONYXKEYS from '../../ONYXKEYS';
-import SCREENS from '../../SCREENS';
-import CONST from '../../CONST';
-let resolveIsReadyPromise;
-let isReadyPromise = new Promise((resolve) => {
+let resolveIsReadyPromise: (value?: Promise) => void | undefined;
+let isReadyPromise = new Promise((resolve) => {
resolveIsReadyPromise = resolve;
});
-let isFirstTimeNewExpensifyUser;
+let isFirstTimeNewExpensifyUser: boolean | undefined;
let isLoadingReportData = true;
-let currentUserAccountID;
+let currentUserAccountID: number | undefined;
+
+type Route = {
+ name: string;
+ params?: {path: string; exitTo?: string; openOnAdminRoom?: boolean};
+};
+
+type ShowParams = {
+ routes: Route[];
+ showCreateMenu?: () => void;
+ showPopoverMenu?: () => boolean;
+};
/**
* Check that a few requests have completed so that the welcome action can proceed:
@@ -26,22 +37,22 @@ let currentUserAccountID;
* - Whether we have loaded all reports the server knows about
*/
function checkOnReady() {
- if (!_.isBoolean(isFirstTimeNewExpensifyUser) || isLoadingReportData) {
+ if (isFirstTimeNewExpensifyUser === undefined || isLoadingReportData) {
return;
}
- resolveIsReadyPromise();
+ resolveIsReadyPromise?.();
}
Onyx.connect({
key: ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER,
initWithStoredValues: false,
- callback: (val) => {
+ callback: (value) => {
// If isFirstTimeNewExpensifyUser was true do not update it to false. We update it to false inside the Welcome.show logic
// More context here https://github.com/Expensify/App/pull/16962#discussion_r1167351359
- if (!isFirstTimeNewExpensifyUser) {
- isFirstTimeNewExpensifyUser = val;
- }
+
+ isFirstTimeNewExpensifyUser = value ?? undefined;
+
checkOnReady();
},
});
@@ -49,13 +60,13 @@ Onyx.connect({
Onyx.connect({
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
initWithStoredValues: false,
- callback: (val) => {
- isLoadingReportData = val;
+ callback: (value) => {
+ isLoadingReportData = value ?? false;
checkOnReady();
},
});
-const allReports = {};
+const allReports: OnyxCollection = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.REPORT,
initWithStoredValues: false,
@@ -68,7 +79,7 @@ Onyx.connect({
},
});
-const allPolicies = {};
+const allPolicies: OnyxCollection = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY,
callback: (val, key) => {
@@ -98,13 +109,8 @@ Onyx.connect({
/**
* Shows a welcome action on first login
- *
- * @param {Object} params
- * @param {Object} params.routes
- * @param {Function} [params.showCreateMenu]
- * @param {Function} [params.showPopoverMenu]
*/
-function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => {}}) {
+function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => false}: ShowParams) {
isReadyPromise.then(() => {
if (!isFirstTimeNewExpensifyUser) {
return;
@@ -112,33 +118,37 @@ function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => {}}) {
// If we are rendering the SidebarScreen at the same time as a workspace route that means we've already created a workspace via workspace/new and should not open the global
// create menu right now. We should also stay on the workspace page if that is our destination.
- const topRoute = _.last(routes);
- const isWorkspaceRoute = topRoute.name === 'Settings' && topRoute.params.path.includes('workspace');
- const transitionRoute = _.find(routes, (route) => route.name === SCREENS.TRANSITION_BETWEEN_APPS);
- const exitingToWorkspaceRoute = lodashGet(transitionRoute, 'params.exitTo', '') === 'workspace/new';
- const openOnAdminRoom = lodashGet(topRoute, 'params.openOnAdminRoom', false);
- const isDisplayingWorkspaceRoute = isWorkspaceRoute || exitingToWorkspaceRoute;
+ const topRoute = routes.length > 0 ? routes[routes.length - 1] : undefined;
+ const isWorkspaceRoute = topRoute !== undefined && topRoute.name === 'Settings' && topRoute.params?.path.includes('workspace');
+ const transitionRoute = routes.find((route) => route.name === SCREENS.TRANSITION_BETWEEN_APPS);
+ const exitingToWorkspaceRoute = transitionRoute?.params?.exitTo === 'workspace/new';
+ const openOnAdminRoom = topRoute?.params?.openOnAdminRoom ?? false;
+ const isDisplayingWorkspaceRoute = isWorkspaceRoute ?? exitingToWorkspaceRoute;
// If we already opened the workspace settings or want the admin room to stay open, do not
// navigate away to the workspace chat report
const shouldNavigateToWorkspaceChat = !isDisplayingWorkspaceRoute && !openOnAdminRoom;
- const workspaceChatReport = _.find(
- allReports,
- (report) => ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS.CLOSED,
- );
+ const workspaceChatReport = Object.values(allReports ?? {}).find((report) => {
+ if (report) {
+ return ReportUtils.isPolicyExpenseChat(report) && report.ownerAccountID === currentUserAccountID && report.statusNum !== CONST.REPORT.STATUS.CLOSED;
+ }
+ return false;
+ });
- if (workspaceChatReport || openOnAdminRoom) {
+ if (workspaceChatReport ?? openOnAdminRoom) {
// This key is only updated when we call ReconnectApp, setting it to false now allows the user to navigate normally instead of always redirecting to the workspace chat
Onyx.set(ONYXKEYS.NVP_IS_FIRST_TIME_NEW_EXPENSIFY_USER, false);
}
if (shouldNavigateToWorkspaceChat && workspaceChatReport) {
- Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReport.reportID));
+ if (workspaceChatReport.reportID !== null) {
+ Navigation.navigate(ROUTES.REPORT_WITH_ID.getRoute(workspaceChatReport.reportID));
+ }
// If showPopoverMenu exists and returns true then it opened the Popover Menu successfully, and we can update isFirstTimeNewExpensifyUser
// so the Welcome logic doesn't run again
- if (showPopoverMenu()) {
+ if (showPopoverMenu?.()) {
isFirstTimeNewExpensifyUser = false;
}
@@ -147,7 +157,7 @@ function show({routes, showCreateMenu = () => {}, showPopoverMenu = () => {}}) {
// If user is not already an admin of a free policy and we are not navigating them to their workspace or creating a new workspace via workspace/new then
// we will show the create menu.
- if (!Policy.isAdminOfFreePolicy(allPolicies) && !isDisplayingWorkspaceRoute) {
+ if (!Policy.isAdminOfFreePolicy(allPolicies ?? undefined) && !isDisplayingWorkspaceRoute) {
showCreateMenu();
}
@@ -164,7 +174,7 @@ function resetReadyCheck() {
isLoadingReportData = true;
}
-function serverDataIsReadyPromise() {
+function serverDataIsReadyPromise(): Promise {
return isReadyPromise;
}
diff --git a/src/libs/addEncryptedAuthTokenToURL.ts b/src/libs/addEncryptedAuthTokenToURL.ts
index 9bdb83c284ce..ea6f0bc6d34d 100644
--- a/src/libs/addEncryptedAuthTokenToURL.ts
+++ b/src/libs/addEncryptedAuthTokenToURL.ts
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
let encryptedAuthToken = '';
Onyx.connect({
diff --git a/src/libs/calculateAnchorPosition.ts b/src/libs/calculateAnchorPosition.ts
index 39fb3032ee09..8db4c053aba6 100644
--- a/src/libs/calculateAnchorPosition.ts
+++ b/src/libs/calculateAnchorPosition.ts
@@ -1,7 +1,7 @@
/* eslint-disable no-console */
-import {ValueOf} from 'type-fest';
import {View} from 'react-native';
-import CONST from '../CONST';
+import {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
type AnchorOrigin = {
horizontal: ValueOf;
diff --git a/src/libs/canFocusInputOnScreenFocus/index.ts b/src/libs/canFocusInputOnScreenFocus/index.ts
index be500074d7e3..57baac02245d 100644
--- a/src/libs/canFocusInputOnScreenFocus/index.ts
+++ b/src/libs/canFocusInputOnScreenFocus/index.ts
@@ -1,4 +1,4 @@
-import * as DeviceCapabilities from '../DeviceCapabilities';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import CanFocusInputOnScreenFocus from './types';
const canFocusInputOnScreenFocus: CanFocusInputOnScreenFocus = () => !DeviceCapabilities.canUseTouchScreen();
diff --git a/src/libs/convertToLTR/index.android.ts b/src/libs/convertToLTR/index.android.ts
index 3a4755b1710f..d73fd3de7a21 100644
--- a/src/libs/convertToLTR/index.android.ts
+++ b/src/libs/convertToLTR/index.android.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import ConvertToLTR from './types';
/**
diff --git a/src/libs/convertToLTRForComposer/index.android.ts b/src/libs/convertToLTRForComposer/index.android.ts
new file mode 100644
index 000000000000..09e7f2e5cd87
--- /dev/null
+++ b/src/libs/convertToLTRForComposer/index.android.ts
@@ -0,0 +1,8 @@
+import ConvertToLTRForComposer from './types';
+
+/**
+ * Android only - Do not convert RTL text to a LTR text for input box using Unicode controls.
+ * Android does not properly support bidirectional text for mixed content for input box
+ */
+const convertToLTRForComposer: ConvertToLTRForComposer = (text) => text;
+export default convertToLTRForComposer;
diff --git a/src/libs/convertToLTRForComposer/index.ts b/src/libs/convertToLTRForComposer/index.ts
new file mode 100644
index 000000000000..37015a755869
--- /dev/null
+++ b/src/libs/convertToLTRForComposer/index.ts
@@ -0,0 +1,35 @@
+import CONST from '@src/CONST';
+import ConvertToLTRForComposer from './types';
+
+function hasRTLCharacters(text: string): boolean {
+ // Regular expressions to match RTL character ranges.
+ const rtlPattern = /[\u0591-\u07FF\uFB1D-\uFDFD\uFE70-\uFEFC]/;
+ return rtlPattern.test(text);
+}
+
+// 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.
+ 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)) {
+ return '';
+ }
+ return text;
+ }
+
+ // Check if the text contains only spaces. If it does, we do not concatenate it with CONST.UNICODE.LTR,
+ // as doing so would alter the normal behavior of the input box.
+ if (/^\s*$/.test(text)) {
+ return text;
+ }
+
+ // Check if the text already starts with the LTR marker (if so, return as is).
+ if (text.startsWith(CONST.UNICODE.LTR)) {
+ return text;
+ }
+
+ // Add the LTR marker to the beginning of the text.
+ return `${CONST.UNICODE.LTR}${text}`;
+};
+export default convertToLTRForComposer;
diff --git a/src/libs/convertToLTRForComposer/types.ts b/src/libs/convertToLTRForComposer/types.ts
new file mode 100644
index 000000000000..c6edeaaba446
--- /dev/null
+++ b/src/libs/convertToLTRForComposer/types.ts
@@ -0,0 +1,3 @@
+type ConvertToLTRForComposer = (text: string) => string;
+
+export default ConvertToLTRForComposer;
diff --git a/src/libs/fileDownload/FileUtils.js b/src/libs/fileDownload/FileUtils.js
index ba06b80f7c43..fab014de302f 100644
--- a/src/libs/fileDownload/FileUtils.js
+++ b/src/libs/fileDownload/FileUtils.js
@@ -1,7 +1,7 @@
import {Alert, Linking, Platform} from 'react-native';
-import CONST from '../../CONST';
-import * as Localize from '../Localize';
-import DateUtils from '../DateUtils';
+import DateUtils from '@libs/DateUtils';
+import * as Localize from '@libs/Localize';
+import CONST from '@src/CONST';
/**
* Show alert on successful attachment download
diff --git a/src/libs/fileDownload/getAttachmentDetails.js b/src/libs/fileDownload/getAttachmentDetails.js
index 72cbad115681..28b678ffb651 100644
--- a/src/libs/fileDownload/getAttachmentDetails.js
+++ b/src/libs/fileDownload/getAttachmentDetails.js
@@ -1,5 +1,5 @@
-import CONST from '../../CONST';
-import tryResolveUrlFromApiRoot from '../tryResolveUrlFromApiRoot';
+import tryResolveUrlFromApiRoot from '@libs/tryResolveUrlFromApiRoot';
+import CONST from '@src/CONST';
/**
* Extract the thumbnail URL, source URL and the original filename from the HTML.
diff --git a/src/libs/fileDownload/index.ios.js b/src/libs/fileDownload/index.ios.js
index 95d92f1e3103..1599e919d28a 100644
--- a/src/libs/fileDownload/index.ios.js
+++ b/src/libs/fileDownload/index.ios.js
@@ -1,8 +1,8 @@
-import RNFetchBlob from 'react-native-blob-util';
import {CameraRoll} from '@react-native-camera-roll/camera-roll';
import lodashGet from 'lodash/get';
+import RNFetchBlob from 'react-native-blob-util';
+import CONST from '@src/CONST';
import * as FileUtils from './FileUtils';
-import CONST from '../../CONST';
/**
* Downloads the file to Documents section in iOS
diff --git a/src/libs/fileDownload/index.js b/src/libs/fileDownload/index.js
index a775576eb365..0b86daf7141f 100644
--- a/src/libs/fileDownload/index.js
+++ b/src/libs/fileDownload/index.js
@@ -1,5 +1,5 @@
+import * as Link from '@userActions/Link';
import * as FileUtils from './FileUtils';
-import * as Link from '../actions/Link';
/**
* Downloading attachment in web, desktop
diff --git a/src/libs/focusAndUpdateMultilineInputRange.ts b/src/libs/focusAndUpdateMultilineInputRange.ts
index 50c3703239df..92da790e383f 100644
--- a/src/libs/focusAndUpdateMultilineInputRange.ts
+++ b/src/libs/focusAndUpdateMultilineInputRange.ts
@@ -1,4 +1,5 @@
import {TextInput} from 'react-native';
+
/**
* Focus a multiline text input and place the cursor at the end of the value (if there is a value in the input).
*
diff --git a/src/libs/getButtonState.ts b/src/libs/getButtonState.ts
index af7c4db6b4ec..6b89e1b7d383 100644
--- a/src/libs/getButtonState.ts
+++ b/src/libs/getButtonState.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
type GetButtonState = (isActive: boolean, isPressed: boolean, isComplete: boolean, isDisabled: boolean, isInteractive: boolean) => ValueOf;
diff --git a/src/libs/getModalState.js b/src/libs/getModalState.js
index 12023a5bdc42..30ff8499809a 100644
--- a/src/libs/getModalState.js
+++ b/src/libs/getModalState.js
@@ -1,5 +1,5 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
+import ONYXKEYS from '@src/ONYXKEYS';
let modalState = {};
diff --git a/src/libs/getOperatingSystem/index.native.ts b/src/libs/getOperatingSystem/index.native.ts
index 38b87f4983b7..f3e856cb14c9 100644
--- a/src/libs/getOperatingSystem/index.native.ts
+++ b/src/libs/getOperatingSystem/index.native.ts
@@ -1,5 +1,5 @@
import {Platform} from 'react-native';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import GetOperatingSystem from './types';
/**
diff --git a/src/libs/getOperatingSystem/index.ts b/src/libs/getOperatingSystem/index.ts
index 7adfa27c45fc..630595d97471 100644
--- a/src/libs/getOperatingSystem/index.ts
+++ b/src/libs/getOperatingSystem/index.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import GetOperatingSystem from './types';
/**
diff --git a/src/libs/getOperatingSystem/types.ts b/src/libs/getOperatingSystem/types.ts
index 64bb103db083..a4b3046b4cd9 100644
--- a/src/libs/getOperatingSystem/types.ts
+++ b/src/libs/getOperatingSystem/types.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
type OS = ValueOf | null;
type GetOperatingSystem = () => OS;
diff --git a/src/libs/getPermittedDecimalSeparator/index.js b/src/libs/getPermittedDecimalSeparator/index.js
index 9ac4156bc3ff..03fa644fc327 100644
--- a/src/libs/getPermittedDecimalSeparator/index.js
+++ b/src/libs/getPermittedDecimalSeparator/index.js
@@ -1,6 +1,6 @@
-import getOperatingSystem from '../getOperatingSystem';
+import getOperatingSystem from '@libs/getOperatingSystem';
+import CONST from '@src/CONST';
import getPermittedDecimalSeparatorIOS from './index.ios';
-import CONST from '../../CONST';
export default (localizedSeparator) => {
if (getOperatingSystem() === CONST.OS.IOS) {
diff --git a/src/libs/getPlaidLinkTokenParameters/index.android.ts b/src/libs/getPlaidLinkTokenParameters/index.android.ts
index 39d444abdba2..c7e2aa8efd1e 100644
--- a/src/libs/getPlaidLinkTokenParameters/index.android.ts
+++ b/src/libs/getPlaidLinkTokenParameters/index.android.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import GetPlaidLinkTokenParameters from './types';
const getPlaidLinkTokenParameters: GetPlaidLinkTokenParameters = () => ({
diff --git a/src/libs/getPlaidLinkTokenParameters/index.ios.ts b/src/libs/getPlaidLinkTokenParameters/index.ios.ts
index 330efad4839a..8c69ddc71bb2 100644
--- a/src/libs/getPlaidLinkTokenParameters/index.ios.ts
+++ b/src/libs/getPlaidLinkTokenParameters/index.ios.ts
@@ -1,4 +1,4 @@
-import CONFIG from '../../CONFIG';
+import CONFIG from '@src/CONFIG';
import GetPlaidLinkTokenParameters from './types';
const getPlaidLinkTokenParameters: GetPlaidLinkTokenParameters = () => ({
diff --git a/src/libs/getPlaidLinkTokenParameters/index.ts b/src/libs/getPlaidLinkTokenParameters/index.ts
index e47629e85d09..570951e3d683 100644
--- a/src/libs/getPlaidLinkTokenParameters/index.ts
+++ b/src/libs/getPlaidLinkTokenParameters/index.ts
@@ -1,5 +1,5 @@
-import ROUTES from '../../ROUTES';
-import CONFIG from '../../CONFIG';
+import CONFIG from '@src/CONFIG';
+import ROUTES from '@src/ROUTES';
import GetPlaidLinkTokenParameters from './types';
const getPlaidLinkTokenParameters: GetPlaidLinkTokenParameters = () => {
diff --git a/src/libs/getPlatform/index.android.ts b/src/libs/getPlatform/index.android.ts
index 14ed65ace19d..a0f4edb055af 100644
--- a/src/libs/getPlatform/index.android.ts
+++ b/src/libs/getPlatform/index.android.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import Platform from './types';
export default function getPlatform(): Platform {
diff --git a/src/libs/getPlatform/index.desktop.ts b/src/libs/getPlatform/index.desktop.ts
index c9f5720c541d..0b90b5f121bb 100644
--- a/src/libs/getPlatform/index.desktop.ts
+++ b/src/libs/getPlatform/index.desktop.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import Platform from './types';
export default function getPlatform(): Platform {
diff --git a/src/libs/getPlatform/index.ios.ts b/src/libs/getPlatform/index.ios.ts
index 8c21189b92e7..ee35c8b610bc 100644
--- a/src/libs/getPlatform/index.ios.ts
+++ b/src/libs/getPlatform/index.ios.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import Platform from './types';
export default function getPlatform(): Platform {
diff --git a/src/libs/getPlatform/index.ts b/src/libs/getPlatform/index.ts
index c53963f5b80f..ca87e79170f5 100644
--- a/src/libs/getPlatform/index.ts
+++ b/src/libs/getPlatform/index.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import Platform from './types';
export default function getPlatform(): Platform {
diff --git a/src/libs/getPlatform/types.ts b/src/libs/getPlatform/types.ts
index ceddb4e17224..9c43c696a6f8 100644
--- a/src/libs/getPlatform/types.ts
+++ b/src/libs/getPlatform/types.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
type Platform = ValueOf;
diff --git a/src/libs/getSecureEntryKeyboardType/index.android.ts b/src/libs/getSecureEntryKeyboardType/index.android.ts
index afd808f35b10..bc50e202381b 100644
--- a/src/libs/getSecureEntryKeyboardType/index.android.ts
+++ b/src/libs/getSecureEntryKeyboardType/index.android.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import GetSecureEntryKeyboardType from './types';
/**
diff --git a/src/libs/isReportMessageAttachment.ts b/src/libs/isReportMessageAttachment.ts
index 8d1112261d1f..097f46465dc9 100644
--- a/src/libs/isReportMessageAttachment.ts
+++ b/src/libs/isReportMessageAttachment.ts
@@ -1,5 +1,5 @@
-import CONST from '../CONST';
-import {Message} from '../types/onyx/ReportAction';
+import CONST from '@src/CONST';
+import {Message} from '@src/types/onyx/ReportAction';
/**
* Check whether a report action is Attachment or not.
diff --git a/src/libs/localFileDownload/index.android.ts b/src/libs/localFileDownload/index.android.ts
index ad13b5c5cfa7..4de6cbd0e940 100644
--- a/src/libs/localFileDownload/index.android.ts
+++ b/src/libs/localFileDownload/index.android.ts
@@ -1,5 +1,5 @@
import RNFetchBlob from 'react-native-blob-util';
-import * as FileUtils from '../fileDownload/FileUtils';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
import LocalFileDownload from './types';
/**
diff --git a/src/libs/localFileDownload/index.ios.ts b/src/libs/localFileDownload/index.ios.ts
index 3597ea5f6d3c..5461c6ffc4c4 100644
--- a/src/libs/localFileDownload/index.ios.ts
+++ b/src/libs/localFileDownload/index.ios.ts
@@ -1,6 +1,6 @@
import {Share} from 'react-native';
import RNFetchBlob from 'react-native-blob-util';
-import * as FileUtils from '../fileDownload/FileUtils';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
import LocalFileDownload from './types';
/**
diff --git a/src/libs/localFileDownload/index.ts b/src/libs/localFileDownload/index.ts
index 7b9b4973d5c1..2a70a01f88c0 100644
--- a/src/libs/localFileDownload/index.ts
+++ b/src/libs/localFileDownload/index.ts
@@ -1,4 +1,4 @@
-import * as FileUtils from '../fileDownload/FileUtils';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
import LocalFileDownload from './types';
/**
diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js
index aaa706e71fb2..b65670819418 100644
--- a/src/libs/migrateOnyx.js
+++ b/src/libs/migrateOnyx.js
@@ -1,5 +1,6 @@
import _ from 'underscore';
import Log from './Log';
+import KeyReportActionsDraftByReportActionID from './migrations/KeyReportActionsDraftByReportActionID';
import PersonalDetailsByAccountID from './migrations/PersonalDetailsByAccountID';
import RenameReceiptFilename from './migrations/RenameReceiptFilename';
@@ -9,7 +10,7 @@ export default function () {
return new Promise((resolve) => {
// Add all migrations to an array so they are executed in order
- const migrationPromises = [PersonalDetailsByAccountID, RenameReceiptFilename];
+ const migrationPromises = [PersonalDetailsByAccountID, RenameReceiptFilename, KeyReportActionsDraftByReportActionID];
// Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the
// previous promise to finish before moving onto the next one.
diff --git a/src/libs/migrations/CheckForPreviousReportActionID.js b/src/libs/migrations/CheckForPreviousReportActionID.js
index a61d9bfb08ec..35f862fd5b3a 100644
--- a/src/libs/migrations/CheckForPreviousReportActionID.js
+++ b/src/libs/migrations/CheckForPreviousReportActionID.js
@@ -1,7 +1,7 @@
-import _ from 'underscore';
import Onyx from 'react-native-onyx';
-import Log from '../Log';
-import ONYXKEYS from '../../ONYXKEYS';
+import _ from 'underscore';
+import Log from '@libs/Log';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* @returns {Promise}
diff --git a/src/libs/migrations/KeyReportActionsDraftByReportActionID.js b/src/libs/migrations/KeyReportActionsDraftByReportActionID.js
new file mode 100644
index 000000000000..e4b3ebd060f3
--- /dev/null
+++ b/src/libs/migrations/KeyReportActionsDraftByReportActionID.js
@@ -0,0 +1,60 @@
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import Log from '@libs/Log';
+import ONYXKEYS from '@src/ONYXKEYS';
+
+/**
+ * This migration updates reportActionsDrafts data to be keyed by reportActionID.
+ *
+ * Before: reportActionsDrafts_reportID_reportActionID: value
+ * After: reportActionsDrafts_reportID: {[reportActionID]: value}
+ *
+ * @returns {Promise}
+ */
+export default function () {
+ return new Promise((resolve) => {
+ const connectionID = Onyx.connect({
+ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS,
+ waitForCollectionCallback: true,
+ callback: (allReportActionsDrafts) => {
+ Onyx.disconnect(connectionID);
+
+ if (!allReportActionsDrafts) {
+ Log.info('[Migrate Onyx] Skipped migration KeyReportActionsDraftByReportActionID because there were no reportActionsDrafts');
+ return resolve();
+ }
+
+ const newReportActionsDrafts = {};
+ _.each(allReportActionsDrafts, (reportActionDraft, onyxKey) => {
+ if (!_.isString(reportActionDraft)) {
+ return;
+ }
+ newReportActionsDrafts[onyxKey] = null;
+
+ if (_.isEmpty(reportActionDraft)) {
+ return;
+ }
+
+ const reportActionID = onyxKey.split('_').pop();
+ const newOnyxKey = onyxKey.replace(`_${reportActionID}`, '');
+
+ // If newReportActionsDrafts[newOnyxKey] isn't set, fall back on the migrated draft if there is one
+ const currentActionsDrafts = newReportActionsDrafts[newOnyxKey] || allReportActionsDrafts[newOnyxKey];
+ newReportActionsDrafts[newOnyxKey] = {
+ ...currentActionsDrafts,
+ [reportActionID]: reportActionDraft,
+ };
+ });
+
+ if (_.isEmpty(newReportActionsDrafts)) {
+ Log.info('[Migrate Onyx] Skipped migration KeyReportActionsDraftByReportActionID because there are no actions drafts to migrate');
+ return resolve();
+ }
+
+ Log.info(`[Migrate Onyx] Re-keying reportActionsDrafts by reportActionID for ${_.keys(newReportActionsDrafts).length} actions drafts`);
+ // eslint-disable-next-line rulesdir/prefer-actions-set-data
+ return Onyx.multiSet(newReportActionsDrafts).then(resolve);
+ },
+ });
+ });
+}
diff --git a/src/libs/migrations/PersonalDetailsByAccountID.js b/src/libs/migrations/PersonalDetailsByAccountID.js
index cf421702fd7a..38c992a6a375 100644
--- a/src/libs/migrations/PersonalDetailsByAccountID.js
+++ b/src/libs/migrations/PersonalDetailsByAccountID.js
@@ -1,8 +1,8 @@
-import _ from 'underscore';
import lodashHas from 'lodash/has';
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import Log from '../Log';
+import _ from 'underscore';
+import Log from '@libs/Log';
+import ONYXKEYS from '@src/ONYXKEYS';
const DEPRECATED_ONYX_KEYS = {
// Deprecated personal details object which was keyed by login instead of accountID.
diff --git a/src/libs/migrations/RenameReceiptFilename.js b/src/libs/migrations/RenameReceiptFilename.js
index b8df705fd7d1..2fcd9662a993 100644
--- a/src/libs/migrations/RenameReceiptFilename.js
+++ b/src/libs/migrations/RenameReceiptFilename.js
@@ -1,8 +1,8 @@
+import lodashHas from 'lodash/has';
import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import lodashHas from 'lodash/has';
-import ONYXKEYS from '../../ONYXKEYS';
-import Log from '../Log';
+import Log from '@libs/Log';
+import ONYXKEYS from '@src/ONYXKEYS';
// This migration changes the property name on a transaction from receiptFilename to filename so that it matches what is stored in the database
export default function () {
diff --git a/src/libs/models/BankAccount.js b/src/libs/models/BankAccount.js
index faf4cbad34e5..c4366a48aa6a 100644
--- a/src/libs/models/BankAccount.js
+++ b/src/libs/models/BankAccount.js
@@ -1,8 +1,8 @@
-import _ from 'underscore';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import lodashHas from 'lodash/has';
-import CONST from '../../CONST';
+import _ from 'underscore';
+import CONST from '@src/CONST';
class BankAccount {
static STATE = {
diff --git a/src/libs/onyxSubscribe.ts b/src/libs/onyxSubscribe.ts
index 469a7b810b1f..5e3213cdcf95 100644
--- a/src/libs/onyxSubscribe.ts
+++ b/src/libs/onyxSubscribe.ts
@@ -1,5 +1,5 @@
import Onyx, {ConnectOptions} from 'react-native-onyx';
-import {OnyxKey} from '../ONYXKEYS';
+import {OnyxKey} from '@src/ONYXKEYS';
/**
* Connect to onyx data. Same params as Onyx.connect(), but returns a function to unsubscribe.
diff --git a/src/libs/setShouldShowComposeInputKeyboardAware/index.native.ts b/src/libs/setShouldShowComposeInputKeyboardAware/index.native.ts
index f5d690db644d..dbfa0c6977b3 100644
--- a/src/libs/setShouldShowComposeInputKeyboardAware/index.native.ts
+++ b/src/libs/setShouldShowComposeInputKeyboardAware/index.native.ts
@@ -1,5 +1,5 @@
import {EmitterSubscription, Keyboard} from 'react-native';
-import * as Composer from '../actions/Composer';
+import * as Composer from '@userActions/Composer';
import SetShouldShowComposeInputKeyboardAware from './types';
let keyboardDidHideListener: EmitterSubscription | null = null;
diff --git a/src/libs/setShouldShowComposeInputKeyboardAware/index.ts b/src/libs/setShouldShowComposeInputKeyboardAware/index.ts
index 5ee36834ad5c..a6217fcd761b 100644
--- a/src/libs/setShouldShowComposeInputKeyboardAware/index.ts
+++ b/src/libs/setShouldShowComposeInputKeyboardAware/index.ts
@@ -1,4 +1,4 @@
-import * as Composer from '../actions/Composer';
+import * as Composer from '@userActions/Composer';
import SetShouldShowComposeInputKeyboardAware from './types';
const setShouldShowComposeInputKeyboardAware: SetShouldShowComposeInputKeyboardAware = (shouldShow) => {
diff --git a/src/libs/tryResolveUrlFromApiRoot.ts b/src/libs/tryResolveUrlFromApiRoot.ts
index 6bfb5473271e..1aa102323a06 100644
--- a/src/libs/tryResolveUrlFromApiRoot.ts
+++ b/src/libs/tryResolveUrlFromApiRoot.ts
@@ -1,5 +1,5 @@
-import Config from '../CONFIG';
-import {Request} from '../types/onyx';
+import Config from '@src/CONFIG';
+import {Request} from '@src/types/onyx';
import * as ApiUtils from './ApiUtils';
// Absolute URLs (`/` or `//`) should be resolved from API ROOT
diff --git a/src/pages/AddPersonalBankAccountPage.js b/src/pages/AddPersonalBankAccountPage.js
index cb53623caa8c..3b802459c98a 100644
--- a/src/pages/AddPersonalBankAccountPage.js
+++ b/src/pages/AddPersonalBankAccountPage.js
@@ -1,22 +1,22 @@
-import _ from 'underscore';
-import React, {useCallback, useEffect, useState} from 'react';
-import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import ScreenWrapper from '../components/ScreenWrapper';
-import Navigation from '../libs/Navigation/Navigation';
-import * as BankAccounts from '../libs/actions/BankAccounts';
-import AddPlaidBankAccount from '../components/AddPlaidBankAccount';
-import getPlaidOAuthReceivedRedirectURI from '../libs/getPlaidOAuthReceivedRedirectURI';
-import ONYXKEYS from '../ONYXKEYS';
-import styles from '../styles/styles';
-import Form from '../components/Form';
-import ROUTES from '../ROUTES';
+import React, {useCallback, useEffect, useState} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import AddPlaidBankAccount from '@components/AddPlaidBankAccount';
+import ConfirmationPage from '@components/ConfirmationPage';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import * as PlaidDataProps from './ReimbursementAccount/plaidDataPropTypes';
-import ConfirmationPage from '../components/ConfirmationPage';
-import * as PaymentMethods from '../libs/actions/PaymentMethods';
-import useLocalize from '../hooks/useLocalize';
const propTypes = {
/** Contains plaid data */
@@ -136,6 +136,7 @@ function AddPersonalBankAccountPage({personalBankAccount, plaidData}) {
AddPersonalBankAccountPage.displayName = 'AddPersonalBankAccountPage';
AddPersonalBankAccountPage.propTypes = propTypes;
AddPersonalBankAccountPage.defaultProps = defaultProps;
+AddPersonalBankAccountPage.displayName = 'AddPersonalBankAccountPage';
export default withOnyx({
personalBankAccount: {
diff --git a/src/pages/ConciergePage.js b/src/pages/ConciergePage.js
index cfd452f0c952..841ce524b2cb 100644
--- a/src/pages/ConciergePage.js
+++ b/src/pages/ConciergePage.js
@@ -1,13 +1,13 @@
-import _ from 'underscore';
-import React from 'react';
+import {useFocusEffect} from '@react-navigation/native';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import {useFocusEffect} from '@react-navigation/native';
-import ONYXKEYS from '../ONYXKEYS';
-import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator';
-import Navigation from '../libs/Navigation/Navigation';
-import * as Report from '../libs/actions/Report';
-import ROUTES from '../ROUTES';
+import _ from 'underscore';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Navigation from '@libs/Navigation/Navigation';
+import * as Report from '@userActions/Report';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Session info for the currently logged in user. */
diff --git a/src/pages/DemoSetupPage.js b/src/pages/DemoSetupPage.js
index 5432bea0c806..9cf0f91906c9 100644
--- a/src/pages/DemoSetupPage.js
+++ b/src/pages/DemoSetupPage.js
@@ -1,11 +1,11 @@
-import React, {useCallback} from 'react';
-import PropTypes from 'prop-types';
import {useFocusEffect} from '@react-navigation/native';
-import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
-import CONST from '../CONST';
-import * as DemoActions from '../libs/actions/DemoActions';
+import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Navigation from '@libs/Navigation/Navigation';
+import * as DemoActions from '@userActions/DemoActions';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Navigation route context info provided by react navigation */
diff --git a/src/pages/DetailsPage.js b/src/pages/DetailsPage.js
index 090e6205e925..7f01256cc024 100755
--- a/src/pages/DetailsPage.js
+++ b/src/pages/DetailsPage.js
@@ -1,33 +1,33 @@
-import React from 'react';
-import {View, ScrollView} from 'react-native';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
-import {withOnyx} from 'react-native-onyx';
+import {parsePhoneNumber} from 'awesome-phonenumber';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
-import {parsePhoneNumber} from 'awesome-phonenumber';
-import styles from '../styles/styles';
-import Text from '../components/Text';
-import ONYXKEYS from '../ONYXKEYS';
-import Avatar from '../components/Avatar';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import ScreenWrapper from '../components/ScreenWrapper';
+import PropTypes from 'prop-types';
+import React from 'react';
+import {ScrollView, View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import AttachmentModal from '@components/AttachmentModal';
+import AutoUpdateTime from '@components/AutoUpdateTime';
+import Avatar from '@components/Avatar';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import CommunicationsLink from '@components/CommunicationsLink';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import UserDetailsTooltip from '@components/UserDetailsTooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import personalDetailsPropType from './personalDetailsPropType';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import compose from '../libs/compose';
-import CommunicationsLink from '../components/CommunicationsLink';
-import UserDetailsTooltip from '../components/UserDetailsTooltip';
-import CONST from '../CONST';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as Expensicons from '../components/Icon/Expensicons';
-import MenuItem from '../components/MenuItem';
-import AttachmentModal from '../components/AttachmentModal';
-import PressableWithoutFocus from '../components/Pressable/PressableWithoutFocus';
-import * as Report from '../libs/actions/Report';
-import OfflineWithFeedback from '../components/OfflineWithFeedback';
-import AutoUpdateTime from '../components/AutoUpdateTime';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
-import * as UserUtils from '../libs/UserUtils';
const matchType = PropTypes.shape({
params: PropTypes.shape({
diff --git a/src/pages/EditRequestAmountPage.js b/src/pages/EditRequestAmountPage.js
index d65fdafb3b59..b986989a81dc 100644
--- a/src/pages/EditRequestAmountPage.js
+++ b/src/pages/EditRequestAmountPage.js
@@ -1,10 +1,10 @@
-import React, {useCallback, useRef} from 'react';
import {useFocusEffect} from '@react-navigation/native';
import PropTypes from 'prop-types';
-import CONST from '../CONST';
-import useLocalize from '../hooks/useLocalize';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
+import React, {useCallback, useRef} from 'react';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import CONST from '@src/CONST';
import MoneyRequestAmountForm from './iou/steps/MoneyRequestAmountForm';
const propTypes = {
diff --git a/src/pages/EditRequestCategoryPage.js b/src/pages/EditRequestCategoryPage.js
index c0db5a16b140..b3eacbe1abad 100644
--- a/src/pages/EditRequestCategoryPage.js
+++ b/src/pages/EditRequestCategoryPage.js
@@ -1,12 +1,12 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Navigation from '../libs/Navigation/Navigation';
-import useLocalize from '../hooks/useLocalize';
-import styles from '../styles/styles';
-import Text from '../components/Text';
-import CategoryPicker from '../components/CategoryPicker';
+import React from 'react';
+import CategoryPicker from '@components/CategoryPicker';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
const propTypes = {
/** Transaction default category value */
diff --git a/src/pages/EditRequestCreatedPage.js b/src/pages/EditRequestCreatedPage.js
index d326e9115afc..5bf421f1d6b0 100644
--- a/src/pages/EditRequestCreatedPage.js
+++ b/src/pages/EditRequestCreatedPage.js
@@ -1,12 +1,12 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import ONYXKEYS from '../ONYXKEYS';
-import styles from '../styles/styles';
-import useLocalize from '../hooks/useLocalize';
-import NewDatePicker from '../components/NewDatePicker';
-import FormProvider from '../components/Form/FormProvider';
+import React from 'react';
+import FormProvider from '@components/Form/FormProvider';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import NewDatePicker from '@components/NewDatePicker';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Transaction defailt created value */
diff --git a/src/pages/EditRequestDescriptionPage.js b/src/pages/EditRequestDescriptionPage.js
index 0c0fcad7f60b..6bbe1aa3a4e8 100644
--- a/src/pages/EditRequestDescriptionPage.js
+++ b/src/pages/EditRequestDescriptionPage.js
@@ -1,17 +1,17 @@
-import React, {useRef, useCallback} from 'react';
-import {View} from 'react-native';
-import PropTypes from 'prop-types';
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 PropTypes from 'prop-types';
+import React, {useCallback, useRef} from 'react';
+import {View} from 'react-native';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import * as Browser from '@libs/Browser';
+import updateMultilineInputRange from '@libs/UpdateMultilineInputRange';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Transaction default description value */
diff --git a/src/pages/EditRequestDistancePage.js b/src/pages/EditRequestDistancePage.js
index 4eb7340dd410..0fca8aee4be9 100644
--- a/src/pages/EditRequestDistancePage.js
+++ b/src/pages/EditRequestDistancePage.js
@@ -1,21 +1,21 @@
-import React, {useEffect, useRef} from 'react';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React, {useEffect, useRef} from 'react';
import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Navigation from '../libs/Navigation/Navigation';
-import useLocalize from '../hooks/useLocalize';
-import DistanceRequest from '../components/DistanceRequest';
+import _ from 'underscore';
+import DistanceRequest from '@components/DistanceRequest';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import transactionPropTypes from '@components/transactionPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import usePrevious from '@hooks/usePrevious';
+import Navigation from '@libs/Navigation/Navigation';
+import * as IOU from '@userActions/IOU';
+import * as TransactionEdit from '@userActions/TransactionEdit';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import reportPropTypes from './reportPropTypes';
-import * as IOU from '../libs/actions/IOU';
-import transactionPropTypes from '../components/transactionPropTypes';
-import * as TransactionEdit from '../libs/actions/TransactionEdit';
-import useNetwork from '../hooks/useNetwork';
-import usePrevious from '../hooks/usePrevious';
const propTypes = {
/** The transactionID we're currently editing */
diff --git a/src/pages/EditRequestMerchantPage.js b/src/pages/EditRequestMerchantPage.js
index 7e15a88a3ab4..e64fd121b4ff 100644
--- a/src/pages/EditRequestMerchantPage.js
+++ b/src/pages/EditRequestMerchantPage.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React, {useCallback, useRef} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-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 Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Transaction default merchant value */
diff --git a/src/pages/EditRequestPage.js b/src/pages/EditRequestPage.js
index f039afeb085f..302b7d35a1c9 100644
--- a/src/pages/EditRequestPage.js
+++ b/src/pages/EditRequestPage.js
@@ -1,35 +1,35 @@
-import React, {useEffect, useMemo} from 'react';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import lodashValues from 'lodash/values';
+import PropTypes from 'prop-types';
+import React, {useEffect, useMemo} from 'react';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import ROUTES from '../ROUTES';
-import compose from '../libs/compose';
-import Navigation from '../libs/Navigation/Navigation';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import * as TransactionUtils from '../libs/TransactionUtils';
-import * as IOU from '../libs/actions/IOU';
-import * as CurrencyUtils from '../libs/CurrencyUtils';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import Permissions from '../libs/Permissions';
-import tagPropTypes from '../components/tagPropTypes';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import categoryPropTypes from '@components/categoryPropTypes';
+import ScreenWrapper from '@components/ScreenWrapper';
+import tagPropTypes from '@components/tagPropTypes';
+import transactionPropTypes from '@components/transactionPropTypes';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import EditRequestAmountPage from './EditRequestAmountPage';
+import EditRequestCategoryPage from './EditRequestCategoryPage';
+import EditRequestCreatedPage from './EditRequestCreatedPage';
import EditRequestDescriptionPage from './EditRequestDescriptionPage';
+import EditRequestDistancePage from './EditRequestDistancePage';
import EditRequestMerchantPage from './EditRequestMerchantPage';
-import EditRequestCreatedPage from './EditRequestCreatedPage';
-import EditRequestAmountPage from './EditRequestAmountPage';
import EditRequestReceiptPage from './EditRequestReceiptPage';
-import reportPropTypes from './reportPropTypes';
-import EditRequestDistancePage from './EditRequestDistancePage';
-import EditRequestCategoryPage from './EditRequestCategoryPage';
import EditRequestTagPage from './EditRequestTagPage';
-import categoryPropTypes from '../components/categoryPropTypes';
-import ScreenWrapper from '../components/ScreenWrapper';
import reportActionPropTypes from './home/report/reportActionPropTypes';
-import transactionPropTypes from '../components/transactionPropTypes';
+import reportPropTypes from './reportPropTypes';
const propTypes = {
/** Route from navigation */
@@ -104,7 +104,7 @@ function EditRequestPage({betas, report, route, parentReport, policyCategories,
const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(report)), [report]);
// A flag for showing the categories page
- const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(betas) && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories)));
+ const shouldShowCategories = isPolicyExpenseChat && (transactionCategory || OptionsListUtils.hasEnabledOptions(lodashValues(policyCategories)));
// A flag for showing the tags page
const shouldShowTags = isPolicyExpenseChat && Permissions.canUseTags(betas) && (transactionTag || OptionsListUtils.hasEnabledOptions(lodashValues(policyTagList)));
diff --git a/src/pages/EditRequestReceiptPage.js b/src/pages/EditRequestReceiptPage.js
index 54ed5a8897a4..9c9daf7c899a 100644
--- a/src/pages/EditRequestReceiptPage.js
+++ b/src/pages/EditRequestReceiptPage.js
@@ -1,13 +1,13 @@
-import React, {useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useState} from 'react';
import {View} from 'react-native';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Navigation from '../libs/Navigation/Navigation';
-import useLocalize from '../hooks/useLocalize';
+import DragAndDropProvider from '@components/DragAndDrop/Provider';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
import ReceiptSelector from './iou/ReceiptSelector';
-import DragAndDropProvider from '../components/DragAndDrop/Provider';
-import styles from '../styles/styles';
const propTypes = {
/** React Navigation route */
diff --git a/src/pages/EditRequestTagPage.js b/src/pages/EditRequestTagPage.js
index c5ae18f1376c..819a026dc9aa 100644
--- a/src/pages/EditRequestTagPage.js
+++ b/src/pages/EditRequestTagPage.js
@@ -1,12 +1,12 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import Navigation from '../libs/Navigation/Navigation';
-import useLocalize from '../hooks/useLocalize';
-import ScreenWrapper from '../components/ScreenWrapper';
-import Text from '../components/Text';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import styles from '../styles/styles';
-import TagPicker from '../components/TagPicker';
+import React from 'react';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TagPicker from '@components/TagPicker';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
const propTypes = {
/** Transaction default tag value */
diff --git a/src/pages/EditSplitBillPage.js b/src/pages/EditSplitBillPage.js
index d10803cd40ea..1342d9297d3e 100644
--- a/src/pages/EditSplitBillPage.js
+++ b/src/pages/EditSplitBillPage.js
@@ -1,21 +1,21 @@
-import React from 'react';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../CONST';
-import ROUTES from '../ROUTES';
-import ONYXKEYS from '../ONYXKEYS';
-import compose from '../libs/compose';
-import transactionPropTypes from '../components/transactionPropTypes';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as IOU from '../libs/actions/IOU';
-import * as CurrencyUtils from '../libs/CurrencyUtils';
-import Navigation from '../libs/Navigation/Navigation';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import transactionPropTypes from '@components/transactionPropTypes';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import EditRequestAmountPage from './EditRequestAmountPage';
+import EditRequestCreatedPage from './EditRequestCreatedPage';
import EditRequestDescriptionPage from './EditRequestDescriptionPage';
import EditRequestMerchantPage from './EditRequestMerchantPage';
-import EditRequestCreatedPage from './EditRequestCreatedPage';
-import EditRequestAmountPage from './EditRequestAmountPage';
const propTypes = {
/** Route from navigation */
diff --git a/src/pages/EnablePayments/ActivateStep.js b/src/pages/EnablePayments/ActivateStep.js
index 2badb5595f3b..30e775a0f932 100644
--- a/src/pages/EnablePayments/ActivateStep.js
+++ b/src/pages/EnablePayments/ActivateStep.js
@@ -1,16 +1,16 @@
-import _ from 'underscore';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import * as LottieAnimations from '../../components/LottieAnimations';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import _ from 'underscore';
+import ConfirmationPage from '@components/ConfirmationPage';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as LottieAnimations from '@components/LottieAnimations';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import userWalletPropTypes from './userWalletPropTypes';
-import CONST from '../../CONST';
-import * as PaymentMethods from '../../libs/actions/PaymentMethods';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
import walletTermsPropTypes from './walletTermsPropTypes';
-import ConfirmationPage from '../../components/ConfirmationPage';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.js b/src/pages/EnablePayments/AdditionalDetailsStep.js
index 13091ab3f845..f1813062d0d7 100644
--- a/src/pages/EnablePayments/AdditionalDetailsStep.js
+++ b/src/pages/EnablePayments/AdditionalDetailsStep.js
@@ -1,28 +1,28 @@
-import _ from 'underscore';
-import React from 'react';
+import {parsePhoneNumber} from 'awesome-phonenumber';
+import {subYears} from 'date-fns';
import PropTypes from 'prop-types';
-import {withOnyx} from 'react-native-onyx';
+import React from 'react';
import {View} from 'react-native';
-import {subYears} from 'date-fns';
-import {parsePhoneNumber} from 'awesome-phonenumber';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import DatePicker from '@components/DatePicker';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import TextLink from '@components/TextLink';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import AddressForm from '@pages/ReimbursementAccount/AddressForm';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import * as Wallet from '@userActions/Wallet';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import IdologyQuestions from './IdologyQuestions';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import styles from '../../styles/styles';
-import Text from '../../components/Text';
-import CONST from '../../CONST';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import TextLink from '../../components/TextLink';
-import TextInput from '../../components/TextInput';
-import * as Wallet from '../../libs/actions/Wallet';
-import * as ValidationUtils from '../../libs/ValidationUtils';
-import AddressForm from '../ReimbursementAccount/AddressForm';
-import DatePicker from '../../components/DatePicker';
-import Form from '../../components/Form';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../components/withCurrentUserPersonalDetails';
-import * as PersonalDetails from '../../libs/actions/PersonalDetails';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/EnablePayments/EnablePaymentsPage.js b/src/pages/EnablePayments/EnablePaymentsPage.js
index 5f1577c3b31b..257eab1d38d3 100644
--- a/src/pages/EnablePayments/EnablePaymentsPage.js
+++ b/src/pages/EnablePayments/EnablePaymentsPage.js
@@ -1,24 +1,23 @@
-import _ from 'underscore';
import React, {useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import * as Wallet from '../../libs/actions/Wallet';
-import ONYXKEYS from '../../ONYXKEYS';
-import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
-import CONST from '../../CONST';
-import userWalletPropTypes from './userWalletPropTypes';
-
+import _ from 'underscore';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import Navigation from '@libs/Navigation/Navigation';
+import * as Wallet from '@userActions/Wallet';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import ActivateStep from './ActivateStep';
+import AdditionalDetailsStep from './AdditionalDetailsStep';
+import FailedKYC from './FailedKYC';
// Steps
import OnfidoStep from './OnfidoStep';
-import AdditionalDetailsStep from './AdditionalDetailsStep';
import TermsStep from './TermsStep';
-import ActivateStep from './ActivateStep';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import FailedKYC from './FailedKYC';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import useLocalize from '../../hooks/useLocalize';
-import useNetwork from '../../hooks/useNetwork';
+import userWalletPropTypes from './userWalletPropTypes';
const propTypes = {
/** The user's wallet */
diff --git a/src/pages/EnablePayments/FailedKYC.js b/src/pages/EnablePayments/FailedKYC.js
index 26b0625a780a..398537cf7645 100644
--- a/src/pages/EnablePayments/FailedKYC.js
+++ b/src/pages/EnablePayments/FailedKYC.js
@@ -1,10 +1,10 @@
import React from 'react';
import {View} from 'react-native';
-import CONST from '../../CONST';
-import Text from '../../components/Text';
-import TextLink from '../../components/TextLink';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import styles from '../../styles/styles';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/EnablePayments/IdologyQuestions.js b/src/pages/EnablePayments/IdologyQuestions.js
index b5f30f93361b..a46e6d54a5ed 100644
--- a/src/pages/EnablePayments/IdologyQuestions.js
+++ b/src/pages/EnablePayments/IdologyQuestions.js
@@ -1,20 +1,20 @@
-import _ from 'underscore';
-import React, {useRef, useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useRef, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as ErrorUtils from '../../libs/ErrorUtils';
-import useLocalize from '../../hooks/useLocalize';
-import RadioButtons from '../../components/RadioButtons';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import Text from '../../components/Text';
-import TextLink from '../../components/TextLink';
-import FormScrollView from '../../components/FormScrollView';
-import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton';
-import OfflineIndicator from '../../components/OfflineIndicator';
-import FixedFooter from '../../components/FixedFooter';
+import _ from 'underscore';
+import FixedFooter from '@components/FixedFooter';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import FormScrollView from '@components/FormScrollView';
+import OfflineIndicator from '@components/OfflineIndicator';
+import RadioButtons from '@components/RadioButtons';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import ONYXKEYS from '@src/ONYXKEYS';
const MAX_SKIP = 1;
const SKIP_QUESTION_TEXT = 'Skip Question';
diff --git a/src/pages/EnablePayments/OnfidoPrivacy.js b/src/pages/EnablePayments/OnfidoPrivacy.js
index 85ceb03b01d5..c195e0237034 100644
--- a/src/pages/EnablePayments/OnfidoPrivacy.js
+++ b/src/pages/EnablePayments/OnfidoPrivacy.js
@@ -1,21 +1,21 @@
+import lodashGet from 'lodash/get';
import React, {useRef} from 'react';
import {View} from 'react-native';
-import lodashGet from 'lodash/get';
-import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
-import FullscreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import styles from '../../styles/styles';
-import TextLink from '../../components/TextLink';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import Text from '../../components/Text';
-import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton';
-import FormScrollView from '../../components/FormScrollView';
+import _ from 'underscore';
+import FixedFooter from '@components/FixedFooter';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import FormScrollView from '@components/FormScrollView';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import ONYXKEYS from '@src/ONYXKEYS';
import walletOnfidoDataPropTypes from './walletOnfidoDataPropTypes';
-import * as ErrorUtils from '../../libs/ErrorUtils';
-import FixedFooter from '../../components/FixedFooter';
const propTypes = {
/** Stores various information used to build the UI and call any APIs */
diff --git a/src/pages/EnablePayments/OnfidoStep.js b/src/pages/EnablePayments/OnfidoStep.js
index fc856d813683..8b40c88f62fb 100644
--- a/src/pages/EnablePayments/OnfidoStep.js
+++ b/src/pages/EnablePayments/OnfidoStep.js
@@ -1,18 +1,18 @@
import React, {useCallback} from 'react';
import {withOnyx} from 'react-native-onyx';
-import Onfido from '../../components/Onfido';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import Navigation from '../../libs/Navigation/Navigation';
-import CONST from '../../CONST';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import * as Wallet from '../../libs/actions/Wallet';
-import useLocalize from '../../hooks/useLocalize';
-import Growl from '../../libs/Growl';
+import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Onfido from '@components/Onfido';
+import useLocalize from '@hooks/useLocalize';
+import Growl from '@libs/Growl';
+import Navigation from '@libs/Navigation/Navigation';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as Wallet from '@userActions/Wallet';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import OnfidoPrivacy from './OnfidoPrivacy';
import walletOnfidoDataPropTypes from './walletOnfidoDataPropTypes';
-import FullPageOfflineBlockingView from '../../components/BlockingViews/FullPageOfflineBlockingView';
-import ROUTES from '../../ROUTES';
const propTypes = {
/** Stores various information used to build the UI and call any APIs */
diff --git a/src/pages/EnablePayments/TermsPage/LongTermsForm.js b/src/pages/EnablePayments/TermsPage/LongTermsForm.js
index 4b68635d8ec8..5a925ad4e7c3 100644
--- a/src/pages/EnablePayments/TermsPage/LongTermsForm.js
+++ b/src/pages/EnablePayments/TermsPage/LongTermsForm.js
@@ -1,14 +1,14 @@
-import _ from 'underscore';
import React from 'react';
import {View} from 'react-native';
-import styles from '../../../styles/styles';
-import Text from '../../../components/Text';
-import CollapsibleSection from '../../../components/CollapsibleSection';
-import * as Localize from '../../../libs/Localize';
-import CONST from '../../../CONST';
-import Icon from '../../../components/Icon';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import TextLink from '../../../components/TextLink';
+import _ from 'underscore';
+import CollapsibleSection from '@components/CollapsibleSection';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import * as Localize from '@libs/Localize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const termsData = [
{
diff --git a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js
index 1b693add95b7..46a1867a2606 100644
--- a/src/pages/EnablePayments/TermsPage/ShortTermsForm.js
+++ b/src/pages/EnablePayments/TermsPage/ShortTermsForm.js
@@ -1,11 +1,11 @@
import React from 'react';
import {View} from 'react-native';
-import styles from '../../../styles/styles';
-import Text from '../../../components/Text';
-import * as Localize from '../../../libs/Localize';
-import CONST from '../../../CONST';
-import TextLink from '../../../components/TextLink';
-import userWalletPropTypes from '../userWalletPropTypes';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import * as Localize from '@libs/Localize';
+import userWalletPropTypes from '@pages/EnablePayments/userWalletPropTypes';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** The user's wallet */
diff --git a/src/pages/EnablePayments/TermsStep.js b/src/pages/EnablePayments/TermsStep.js
index c11d8c39bda6..6dff94b7202b 100644
--- a/src/pages/EnablePayments/TermsStep.js
+++ b/src/pages/EnablePayments/TermsStep.js
@@ -1,21 +1,21 @@
import React, {useEffect, useState} from 'react';
import {ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import styles from '../../styles/styles';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import TextLink from '../../components/TextLink';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import CheckboxWithLabel from '../../components/CheckboxWithLabel';
-import Text from '../../components/Text';
-import ShortTermsForm from './TermsPage/ShortTermsForm';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import ONYXKEYS from '@src/ONYXKEYS';
import LongTermsForm from './TermsPage/LongTermsForm';
-import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton';
-import walletTermsPropTypes from './walletTermsPropTypes';
-import * as ErrorUtils from '../../libs/ErrorUtils';
+import ShortTermsForm from './TermsPage/ShortTermsForm';
import userWalletPropTypes from './userWalletPropTypes';
+import walletTermsPropTypes from './walletTermsPropTypes';
const propTypes = {
/** The user's wallet */
diff --git a/src/pages/EnablePayments/walletTermsPropTypes.js b/src/pages/EnablePayments/walletTermsPropTypes.js
index 44d153f3b6ff..4420a2dd0861 100644
--- a/src/pages/EnablePayments/walletTermsPropTypes.js
+++ b/src/pages/EnablePayments/walletTermsPropTypes.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
import _ from 'underscore';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
/** Prop types related to the Terms step of KYC flow */
export default PropTypes.shape({
diff --git a/src/pages/ErrorPage/ErrorBodyText/index.js b/src/pages/ErrorPage/ErrorBodyText/index.js
index 9410d5fe5c1d..d50d15c15cd0 100644
--- a/src/pages/ErrorPage/ErrorBodyText/index.js
+++ b/src/pages/ErrorPage/ErrorBodyText/index.js
@@ -1,9 +1,9 @@
import React from 'react';
-import Text from '../../../components/Text';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import TextLink from '../../../components/TextLink';
-import CONST from '../../../CONST';
-import styles from '../../../styles/styles';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/ErrorPage/GenericErrorPage.js b/src/pages/ErrorPage/GenericErrorPage.js
index 02ab38a1ef20..af551fe5743a 100644
--- a/src/pages/ErrorPage/GenericErrorPage.js
+++ b/src/pages/ErrorPage/GenericErrorPage.js
@@ -1,21 +1,21 @@
import React from 'react';
-import {View} from 'react-native';
import {useErrorBoundary} from 'react-error-boundary';
-import Icon from '../../components/Icon';
-import defaultTheme from '../../styles/themes/default';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import Text from '../../components/Text';
-import Button from '../../components/Button';
-import LogoWordmark from '../../../assets/images/expensify-wordmark.svg';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import * as Session from '../../libs/actions/Session';
-import variables from '../../styles/variables';
-import styles from '../../styles/styles';
+import {View} from 'react-native';
+import LogoWordmark from '@assets/images/expensify-wordmark.svg';
+import Button from '@components/Button';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import SafeAreaConsumer from '@components/SafeAreaConsumer';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import defaultTheme from '@styles/themes/default';
+import variables from '@styles/variables';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
import ErrorBodyText from './ErrorBodyText';
-import TextLink from '../../components/TextLink';
-import CONST from '../../CONST';
-import SafeAreaConsumer from '../../components/SafeAreaConsumer';
-import * as StyleUtils from '../../styles/StyleUtils';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/ErrorPage/NotFoundPage.js b/src/pages/ErrorPage/NotFoundPage.js
index 445e81296566..9ada6b820e8e 100644
--- a/src/pages/ErrorPage/NotFoundPage.js
+++ b/src/pages/ErrorPage/NotFoundPage.js
@@ -1,6 +1,6 @@
import React from 'react';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import ScreenWrapper from '@components/ScreenWrapper';
// eslint-disable-next-line rulesdir/no-negated-variables
function NotFoundPage() {
diff --git a/src/pages/FlagCommentPage.js b/src/pages/FlagCommentPage.js
index 53da810007ea..ee7b2d8af3c1 100644
--- a/src/pages/FlagCommentPage.js
+++ b/src/pages/FlagCommentPage.js
@@ -1,27 +1,27 @@
-import React, {useCallback} from 'react';
-import _ from 'underscore';
-import {View, ScrollView} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import reportPropTypes from './reportPropTypes';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import reportActionPropTypes from './home/report/reportActionPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import compose from '../libs/compose';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import styles from '../styles/styles';
-import Navigation from '../libs/Navigation/Navigation';
-import Text from '../components/Text';
-import * as Expensicons from '../components/Icon/Expensicons';
-import MenuItem from '../components/MenuItem';
-import * as Report from '../libs/actions/Report';
-import CONST from '../CONST';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as ReportActionsUtils from '../libs/ReportActionsUtils';
-import * as Session from '../libs/actions/Session';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
import withReportAndReportActionOrNotFound from './home/report/withReportAndReportActionOrNotFound';
-import ONYXKEYS from '../ONYXKEYS';
+import reportPropTypes from './reportPropTypes';
const propTypes = {
/** Array of report actions for this report */
diff --git a/src/pages/GetAssistancePage.js b/src/pages/GetAssistancePage.js
index 97b498d758b7..647734a0cde1 100644
--- a/src/pages/GetAssistancePage.js
+++ b/src/pages/GetAssistancePage.js
@@ -1,23 +1,23 @@
-import React from 'react';
-import {View, ScrollView} from 'react-native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React from 'react';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Section from '../components/Section';
-import styles from '../styles/styles';
-import Text from '../components/Text';
-import * as Expensicons from '../components/Icon/Expensicons';
-import * as Illustrations from '../components/Icon/Illustrations';
-import * as Report from '../libs/actions/Report';
-import * as Link from '../libs/actions/Link';
-import CONST from '../CONST';
-import compose from '../libs/compose';
-import ONYXKEYS from '../ONYXKEYS';
-import Navigation from '../libs/Navigation/Navigation';
-import ROUTES from '../ROUTES';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Route object from navigation */
diff --git a/src/pages/KeyboardShortcutsPage.js b/src/pages/KeyboardShortcutsPage.js
index 8ac26301e9fb..4caade5b9ec1 100644
--- a/src/pages/KeyboardShortcutsPage.js
+++ b/src/pages/KeyboardShortcutsPage.js
@@ -1,14 +1,14 @@
import React from 'react';
-import {View, ScrollView} from 'react-native';
+import {ScrollView, View} from 'react-native';
import _ from 'underscore';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import ScreenWrapper from '../components/ScreenWrapper';
-import Text from '../components/Text';
-import styles from '../styles/styles';
-import CONST from '../CONST';
-import useLocalize from '../hooks/useLocalize';
-import KeyboardShortcut from '../libs/KeyboardShortcut';
-import MenuItem from '../components/MenuItem';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItem from '@components/MenuItem';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
function KeyboardShortcutsPage() {
const {translate} = useLocalize();
diff --git a/src/pages/LogInWithShortLivedAuthTokenPage.js b/src/pages/LogInWithShortLivedAuthTokenPage.js
index 875cdf7e8072..84de67e496b5 100644
--- a/src/pages/LogInWithShortLivedAuthTokenPage.js
+++ b/src/pages/LogInWithShortLivedAuthTokenPage.js
@@ -1,20 +1,20 @@
-import React, {useEffect} from 'react';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import {withOnyx} from 'react-native-onyx';
+import React, {useEffect} from 'react';
import {View} from 'react-native';
-import Text from '../components/Text';
-import * as Session from '../libs/actions/Session';
-import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator';
-import Navigation from '../libs/Navigation/Navigation';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import Icon from '../components/Icon';
-import * as Expensicons from '../components/Icon/Expensicons';
-import * as Illustrations from '../components/Icon/Illustrations';
-import useLocalize from '../hooks/useLocalize';
-import TextLink from '../components/TextLink';
-import ONYXKEYS from '../ONYXKEYS';
+import {withOnyx} from 'react-native-onyx';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The parameters needed to authenticate with a short-lived token are in the URL */
diff --git a/src/pages/LogOutPreviousUserPage.js b/src/pages/LogOutPreviousUserPage.js
index 9055187def16..8fd0ec144a1f 100644
--- a/src/pages/LogOutPreviousUserPage.js
+++ b/src/pages/LogOutPreviousUserPage.js
@@ -1,12 +1,12 @@
-import React, {useEffect} from 'react';
-import {Linking} from 'react-native';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
+import {Linking} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
-import * as Session from '../libs/actions/Session';
-import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator';
-import * as SessionUtils from '../libs/SessionUtils';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import * as SessionUtils from '@libs/SessionUtils';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The data about the current session which will be set once the user is authenticated and we return to this component as an AuthScreen */
diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js
index 381564b82600..25a1bed4f11a 100755
--- a/src/pages/NewChatPage.js
+++ b/src/pages/NewChatPage.js
@@ -1,27 +1,27 @@
-import _ from 'underscore';
-import React, {useState, useEffect, useMemo, useCallback} from 'react';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import OptionsSelector from '../components/OptionsSelector';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import Permissions from '../libs/Permissions';
-import * as ReportUtils from '../libs/ReportUtils';
-import ONYXKEYS from '../ONYXKEYS';
-import styles from '../styles/styles';
-import * as Report from '../libs/actions/Report';
-import CONST from '../CONST';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../components/withWindowDimensions';
-import ScreenWrapper from '../components/ScreenWrapper';
-import KeyboardAvoidingView from '../components/KeyboardAvoidingView';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import * as Browser from '../libs/Browser';
-import compose from '../libs/compose';
+import _ from 'underscore';
+import KeyboardAvoidingView from '@components/KeyboardAvoidingView';
+import OptionsSelector from '@components/OptionsSelector';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useDelayedInputFocus from '@hooks/useDelayedInputFocus';
+import useNetwork from '@hooks/useNetwork';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import personalDetailsPropType from './personalDetailsPropType';
import reportPropTypes from './reportPropTypes';
-import variables from '../styles/variables';
-import useNetwork from '../hooks/useNetwork';
-import useDelayedInputFocus from '../hooks/useDelayedInputFocus';
const propTypes = {
/** Beta features list */
diff --git a/src/pages/NewChatSelectorPage.js b/src/pages/NewChatSelectorPage.js
index 2ac2ed8177a1..6e970c80b1cb 100755
--- a/src/pages/NewChatSelectorPage.js
+++ b/src/pages/NewChatSelectorPage.js
@@ -1,17 +1,17 @@
import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import OnyxTabNavigator, {TopTab} from '../libs/Navigation/OnyxTabNavigator';
-import TabSelector from '../components/TabSelector/TabSelector';
-import Permissions from '../libs/Permissions';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TabSelector from '@components/TabSelector/TabSelector';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import OnyxTabNavigator, {TopTab} from '@libs/Navigation/OnyxTabNavigator';
+import Permissions from '@libs/Permissions';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import NewChatPage from './NewChatPage';
import WorkspaceNewRoomPage from './workspace/WorkspaceNewRoomPage';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../components/withWindowDimensions';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import ScreenWrapper from '../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import compose from '../libs/compose';
const propTypes = {
...windowDimensionsPropTypes,
diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.js b/src/pages/PrivateNotes/PrivateNotesEditPage.js
index b61e7bca7a76..b31e9b58cbe9 100644
--- a/src/pages/PrivateNotes/PrivateNotesEditPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js
@@ -1,32 +1,33 @@
-import React, {useState, useRef, useCallback, useMemo} from 'react';
+import {useFocusEffect} from '@react-navigation/native';
+import ExpensiMark from 'expensify-common/lib/ExpensiMark';
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useMemo, useRef, useState} from 'react';
import {Keyboard} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import {useFocusEffect} from '@react-navigation/native';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
-import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import _ from 'underscore';
-import withLocalize from '../../components/withLocalize';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import TextInput from '../../components/TextInput';
-import CONST from '../../CONST';
-import Text from '../../components/Text';
-import Form from '../../components/Form';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import reportPropTypes from '../reportPropTypes';
-import personalDetailsPropType from '../personalDetailsPropType';
-import * as Report from '../../libs/actions/Report';
-import useLocalize from '../../hooks/useLocalize';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
-import updateMultilineInputRange from '../../libs/UpdateMultilineInputRange';
-import ROUTES from '../../ROUTES';
-import * as ReportUtils from '../../libs/ReportUtils';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import updateMultilineInputRange from '@libs/UpdateMultilineInputRange';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** All of the personal details for everyone */
@@ -64,7 +65,7 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
// We need to edit the note in markdown format, but display it in HTML format
const parser = new ExpensiMark();
const [privateNote, setPrivateNote] = useState(
- Report.getDraftPrivateNote(report.reportID) || parser.htmlToMarkdown(lodashGet(report, ['privateNotes', route.params.accountID, 'note'], '')).trim(),
+ () => Report.getDraftPrivateNote(report.reportID).trim() || parser.htmlToMarkdown(lodashGet(report, ['privateNotes', route.params.accountID, 'note'], '')).trim(),
);
/**
@@ -135,7 +136,7 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
shouldShowBackButton
onCloseButtonPress={() => Navigation.dismissModal()}
/>
-
+
);
diff --git a/src/pages/PrivateNotes/PrivateNotesListPage.js b/src/pages/PrivateNotes/PrivateNotesListPage.js
index bd49e74d5f69..ec3905db349e 100644
--- a/src/pages/PrivateNotes/PrivateNotesListPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesListPage.js
@@ -1,30 +1,30 @@
-import React, {useMemo, useEffect} from 'react';
-import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useEffect, useMemo} from 'react';
import {ScrollView} from 'react-native';
-import Navigation from '../../libs/Navigation/Navigation';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
-import MenuItem from '../../components/MenuItem';
-import useLocalize from '../../hooks/useLocalize';
-import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
-import * as Report from '../../libs/actions/Report';
-import personalDetailsPropType from '../personalDetailsPropType';
-import * as UserUtils from '../../libs/UserUtils';
-import reportPropTypes from '../reportPropTypes';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import {withNetwork} from '../../components/OnyxProvider';
-import networkPropTypes from '../../components/networkPropTypes';
-import ROUTES from '../../ROUTES';
-import * as ReportUtils from '../../libs/ReportUtils';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItem from '@components/MenuItem';
+import networkPropTypes from '@components/networkPropTypes';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {withNetwork} from '@components/OnyxProvider';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** The report currently being looked at */
diff --git a/src/pages/PrivateNotes/PrivateNotesViewPage.js b/src/pages/PrivateNotes/PrivateNotesViewPage.js
index 6550c9d7d3c3..bb9d96516437 100644
--- a/src/pages/PrivateNotes/PrivateNotesViewPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesViewPage.js
@@ -1,25 +1,25 @@
-import React from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React from 'react';
import {ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import withLocalize from '../../components/withLocalize';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import ROUTES from '../../ROUTES';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import reportPropTypes from '../reportPropTypes';
-import personalDetailsPropType from '../personalDetailsPropType';
-import useLocalize from '../../hooks/useLocalize';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
-import MenuItemWithTopDescription from '../../components/MenuItemWithTopDescription';
-import CONST from '../../CONST';
-import * as ReportUtils from '../../libs/ReportUtils';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** All of the personal details for everyone */
diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js
index 8e0ed04ab94a..ccc5cd14359a 100755
--- a/src/pages/ProfilePage.js
+++ b/src/pages/ProfilePage.js
@@ -1,43 +1,43 @@
-import {View, ScrollView} from 'react-native';
-import React, {useEffect} from 'react';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
-import {withOnyx} from 'react-native-onyx';
+import {parsePhoneNumber} from 'awesome-phonenumber';
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
-import {parsePhoneNumber} from 'awesome-phonenumber';
-import * as Session from '../libs/actions/Session';
-import styles from '../styles/styles';
-import Text from '../components/Text';
-import ONYXKEYS from '../ONYXKEYS';
-import Avatar from '../components/Avatar';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Navigation from '../libs/Navigation/Navigation';
-import ScreenWrapper from '../components/ScreenWrapper';
+import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
+import {ScrollView, View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import AttachmentModal from '@components/AttachmentModal';
+import AutoUpdateTime from '@components/AutoUpdateTime';
+import Avatar from '@components/Avatar';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import CommunicationsLink from '@components/CommunicationsLink';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithoutFocus from '@components/Pressable/PressableWithoutFocus';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import UserDetailsTooltip from '@components/UserDetailsTooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import * as Report from '@userActions/Report';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import personalDetailsPropType from './personalDetailsPropType';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import compose from '../libs/compose';
-import CommunicationsLink from '../components/CommunicationsLink';
-import UserDetailsTooltip from '../components/UserDetailsTooltip';
-import CONST from '../CONST';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as Expensicons from '../components/Icon/Expensicons';
-import MenuItem from '../components/MenuItem';
-import AttachmentModal from '../components/AttachmentModal';
-import PressableWithoutFocus from '../components/Pressable/PressableWithoutFocus';
-import * as Report from '../libs/actions/Report';
-import OfflineWithFeedback from '../components/OfflineWithFeedback';
-import AutoUpdateTime from '../components/AutoUpdateTime';
-import * as UserUtils from '../libs/UserUtils';
-import * as PersonalDetails from '../libs/actions/PersonalDetails';
-import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator';
-import BlockingView from '../components/BlockingViews/BlockingView';
-import * as Illustrations from '../components/Icon/Illustrations';
-import variables from '../styles/variables';
-import * as ValidationUtils from '../libs/ValidationUtils';
-import Permissions from '../libs/Permissions';
-import ROUTES from '../ROUTES';
-import MenuItemWithTopDescription from '../components/MenuItemWithTopDescription';
const matchType = PropTypes.shape({
params: PropTypes.shape({
diff --git a/src/pages/ReimbursementAccount/ACHContractStep.js b/src/pages/ReimbursementAccount/ACHContractStep.js
index 761be71d864a..8f2d2e07998e 100644
--- a/src/pages/ReimbursementAccount/ACHContractStep.js
+++ b/src/pages/ReimbursementAccount/ACHContractStep.js
@@ -1,23 +1,23 @@
-import _ from 'underscore';
+import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
-import React, {useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useState} from 'react';
import {View} from 'react-native';
-import Str from 'expensify-common/lib/str';
-import Text from '../../components/Text';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import styles from '../../styles/styles';
-import CheckboxWithLabel from '../../components/CheckboxWithLabel';
-import TextLink from '../../components/TextLink';
+import _ from 'underscore';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize from '@components/withLocalize';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as FormActions from '@userActions/FormActions';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import IdentityForm from './IdentityForm';
-import withLocalize from '../../components/withLocalize';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import CONST from '../../CONST';
-import * as ValidationUtils from '../../libs/ValidationUtils';
-import ONYXKEYS from '../../ONYXKEYS';
-import Form from '../../components/Form';
-import * as FormActions from '../../libs/actions/FormActions';
-import ScreenWrapper from '../../components/ScreenWrapper';
import StepPropTypes from './StepPropTypes';
const propTypes = {
@@ -28,7 +28,7 @@ const propTypes = {
};
function ACHContractStep(props) {
- const [beneficialOwners, setBeneficialOwners] = useState(
+ const [beneficialOwners, setBeneficialOwners] = useState(() =>
lodashGet(props.reimbursementAccountDraft, 'beneficialOwners', lodashGet(props.reimbursementAccount, 'achData.beneficialOwners', [])),
);
diff --git a/src/pages/ReimbursementAccount/AddressForm.js b/src/pages/ReimbursementAccount/AddressForm.js
index 5ddea09c6f4e..36fbc6e4c59d 100644
--- a/src/pages/ReimbursementAccount/AddressForm.js
+++ b/src/pages/ReimbursementAccount/AddressForm.js
@@ -1,11 +1,11 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import TextInput from '../../components/TextInput';
-import AddressSearch from '../../components/AddressSearch';
-import styles from '../../styles/styles';
-import CONST from '../../CONST';
-import StatePicker from '../../components/StatePicker';
+import AddressSearch from '@components/AddressSearch';
+import StatePicker from '@components/StatePicker';
+import TextInput from '@components/TextInput';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Translate key for Street name */
diff --git a/src/pages/ReimbursementAccount/BankAccountManualStep.js b/src/pages/ReimbursementAccount/BankAccountManualStep.js
index 9d0b0c1f5bed..13155d286a5e 100644
--- a/src/pages/ReimbursementAccount/BankAccountManualStep.js
+++ b/src/pages/ReimbursementAccount/BankAccountManualStep.js
@@ -1,23 +1,23 @@
+import lodashGet from 'lodash/get';
import React, {useCallback} from 'react';
-import _ from 'underscore';
import {Image} from 'react-native';
-import lodashGet from 'lodash/get';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import CONST from '../../CONST';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import Text from '../../components/Text';
-import TextInput from '../../components/TextInput';
-import styles from '../../styles/styles';
-import CheckboxWithLabel from '../../components/CheckboxWithLabel';
-import TextLink from '../../components/TextLink';
-import useLocalize from '../../hooks/useLocalize';
-import {withLocalizePropTypes} from '../../components/withLocalize';
-import * as ValidationUtils from '../../libs/ValidationUtils';
-import ONYXKEYS from '../../ONYXKEYS';
+import _ from 'underscore';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import TextLink from '@components/TextLink';
+import {withLocalizePropTypes} from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import shouldDelayFocus from '@libs/shouldDelayFocus';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import exampleCheckImage from './exampleCheckImage';
-import Form from '../../components/Form';
-import shouldDelayFocus from '../../libs/shouldDelayFocus';
-import ScreenWrapper from '../../components/ScreenWrapper';
import StepPropTypes from './StepPropTypes';
const propTypes = {
diff --git a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js
index 3fbf2a138384..06e8c0531e3b 100644
--- a/src/pages/ReimbursementAccount/BankAccountPlaidStep.js
+++ b/src/pages/ReimbursementAccount/BankAccountPlaidStep.js
@@ -1,23 +1,23 @@
-import React, {useCallback, useEffect} from 'react';
import {useIsFocused} from '@react-navigation/native';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import CONST from '../../CONST';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import withLocalize from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import AddPlaidBankAccount from '../../components/AddPlaidBankAccount';
-import CheckboxWithLabel from '../../components/CheckboxWithLabel';
-import TextLink from '../../components/TextLink';
-import Text from '../../components/Text';
-import * as ReimbursementAccount from '../../libs/actions/ReimbursementAccount';
-import Form from '../../components/Form';
-import styles from '../../styles/styles';
-import ScreenWrapper from '../../components/ScreenWrapper';
+import _ from 'underscore';
+import AddPlaidBankAccount from '@components/AddPlaidBankAccount';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize from '@components/withLocalize';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as ReimbursementAccount from '@userActions/ReimbursementAccount';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as PlaidDataProps from './plaidDataPropTypes';
import StepPropTypes from './StepPropTypes';
diff --git a/src/pages/ReimbursementAccount/BankAccountStep.js b/src/pages/ReimbursementAccount/BankAccountStep.js
index b01b46f69350..f1bc41d44ed5 100644
--- a/src/pages/ReimbursementAccount/BankAccountStep.js
+++ b/src/pages/ReimbursementAccount/BankAccountStep.js
@@ -1,33 +1,33 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
-import {View, ScrollView} from 'react-native';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
+import Button from '@components/Button';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import MenuItem from '@components/MenuItem';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize from '@components/withLocalize';
+import compose from '@libs/compose';
+import getPlaidDesktopMessage from '@libs/getPlaidDesktopMessage';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as Link from '@userActions/Link';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import BankAccountManualStep from './BankAccountManualStep';
import BankAccountPlaidStep from './BankAccountPlaidStep';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import MenuItem from '../../components/MenuItem';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import styles from '../../styles/styles';
-import TextLink from '../../components/TextLink';
-import Icon from '../../components/Icon';
-import themeColors from '../../styles/themes/default';
-import CONST from '../../CONST';
-import withLocalize from '../../components/withLocalize';
-import Text from '../../components/Text';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import ONYXKEYS from '../../ONYXKEYS';
-import compose from '../../libs/compose';
-import Section from '../../components/Section';
-import * as Illustrations from '../../components/Icon/Illustrations';
-import getPlaidDesktopMessage from '../../libs/getPlaidDesktopMessage';
-import CONFIG from '../../CONFIG';
-import ROUTES from '../../ROUTES';
-import Button from '../../components/Button';
-import ScreenWrapper from '../../components/ScreenWrapper';
import StepPropTypes from './StepPropTypes';
-import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback';
-import * as Link from '../../libs/actions/Link';
const propTypes = {
...StepPropTypes,
diff --git a/src/pages/ReimbursementAccount/CompanyStep.js b/src/pages/ReimbursementAccount/CompanyStep.js
index 0ca9b1b7ea92..24cfbf5ae4c6 100644
--- a/src/pages/ReimbursementAccount/CompanyStep.js
+++ b/src/pages/ReimbursementAccount/CompanyStep.js
@@ -1,29 +1,29 @@
-import _ from 'underscore';
+import {parsePhoneNumber} from 'awesome-phonenumber';
+import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
import {View} from 'react-native';
-import Str from 'expensify-common/lib/str';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import {parsePhoneNumber} from 'awesome-phonenumber';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import StatePicker from '../../components/StatePicker';
-import CONST from '../../CONST';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import Text from '../../components/Text';
-import DatePicker from '../../components/DatePicker';
-import TextInput from '../../components/TextInput';
-import styles from '../../styles/styles';
-import CheckboxWithLabel from '../../components/CheckboxWithLabel';
-import TextLink from '../../components/TextLink';
-import withLocalize from '../../components/withLocalize';
-import * as ValidationUtils from '../../libs/ValidationUtils';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import Picker from '../../components/Picker';
+import _ from 'underscore';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import DatePicker from '@components/DatePicker';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Picker from '@components/Picker';
+import ScreenWrapper from '@components/ScreenWrapper';
+import StatePicker from '@components/StatePicker';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import TextLink from '@components/TextLink';
+import withLocalize from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import AddressForm from './AddressForm';
-import Form from '../../components/Form';
-import ScreenWrapper from '../../components/ScreenWrapper';
import StepPropTypes from './StepPropTypes';
const propTypes = {
diff --git a/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js b/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js
index 5bde2884be51..52ccc3b87835 100644
--- a/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js
+++ b/src/pages/ReimbursementAccount/ContinueBankAccountSetup.js
@@ -1,23 +1,23 @@
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React from 'react';
import {ScrollView} from 'react-native';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import * as Illustrations from '../../components/Icon/Illustrations';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import Button from '../../components/Button';
-import CONST from '../../CONST';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import MenuItem from '../../components/MenuItem';
-import styles from '../../styles/styles';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import Section from '../../components/Section';
-import Text from '../../components/Text';
+import Button from '@components/Button';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
-import WorkspaceResetBankAccountModal from '../workspace/WorkspaceResetBankAccountModal';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
const propTypes = {
/** Bank account currently in setup */
diff --git a/src/pages/ReimbursementAccount/Enable2FAPrompt.js b/src/pages/ReimbursementAccount/Enable2FAPrompt.js
index 33424669903f..c768f901508e 100644
--- a/src/pages/ReimbursementAccount/Enable2FAPrompt.js
+++ b/src/pages/ReimbursementAccount/Enable2FAPrompt.js
@@ -1,13 +1,13 @@
import React from 'react';
import {View} from 'react-native';
-import Text from '../../components/Text';
-import styles from '../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import * as Illustrations from '../../components/Icon/Illustrations';
-import Section from '../../components/Section';
-import * as Link from '../../libs/actions/Link';
-import ROUTES from '../../ROUTES';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/ReimbursementAccount/EnableStep.js b/src/pages/ReimbursementAccount/EnableStep.js
index 6612a0b6ad2f..cb59a4bc97f5 100644
--- a/src/pages/ReimbursementAccount/EnableStep.js
+++ b/src/pages/ReimbursementAccount/EnableStep.js
@@ -1,29 +1,29 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'underscore';
import {ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import styles from '../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Text from '../../components/Text';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import Button from '../../components/Button';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import MenuItem from '../../components/MenuItem';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
-import getBankIcon from '../../components/Icon/BankIcons';
+import _ from 'underscore';
+import Button from '@components/Button';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import getBankIcon from '@components/Icon/BankIcons';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import userPropTypes from '@pages/settings/userPropTypes';
+import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import * as BankAccounts from '@userActions/ReimbursementAccount';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
-import userPropTypes from '../settings/userPropTypes';
-import Section from '../../components/Section';
-import * as Illustrations from '../../components/Icon/Illustrations';
-import * as Link from '../../libs/actions/Link';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import * as BankAccounts from '../../libs/actions/ReimbursementAccount';
-import WorkspaceResetBankAccountModal from '../workspace/WorkspaceResetBankAccountModal';
const propTypes = {
/** Bank account currently in setup */
diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js
index 20c6e10ec64d..7cd66f3ba086 100644
--- a/src/pages/ReimbursementAccount/IdentityForm.js
+++ b/src/pages/ReimbursementAccount/IdentityForm.js
@@ -1,12 +1,12 @@
+import {subYears} from 'date-fns';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import {subYears} from 'date-fns';
import _ from 'underscore';
-import TextInput from '../../components/TextInput';
-import styles from '../../styles/styles';
-import CONST from '../../CONST';
-import DatePicker from '../../components/DatePicker';
+import DatePicker from '@components/DatePicker';
+import TextInput from '@components/TextInput';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
import AddressForm from './AddressForm';
const propTypes = {
diff --git a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js
index 398a6a7c6c93..35fa1261f9dc 100644
--- a/src/pages/ReimbursementAccount/ReimbursementAccountPage.js
+++ b/src/pages/ReimbursementAccount/ReimbursementAccountPage.js
@@ -1,39 +1,39 @@
-import _ from 'underscore';
+import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
-import {withOnyx} from 'react-native-onyx';
-import Str from 'expensify-common/lib/str';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import ONYXKEYS from '../../ONYXKEYS';
-import ReimbursementAccountLoadingIndicator from '../../components/ReimbursementAccountLoadingIndicator';
-import Navigation from '../../libs/Navigation/Navigation';
-import CONST from '../../CONST';
-import BankAccount from '../../libs/models/BankAccount';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import styles from '../../styles/styles';
-import getPlaidOAuthReceivedRedirectURI from '../../libs/getPlaidOAuthReceivedRedirectURI';
-import Text from '../../components/Text';
-import {withNetwork} from '../../components/OnyxProvider';
-import networkPropTypes from '../../components/networkPropTypes';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import ReimbursementAccountLoadingIndicator from '@components/ReimbursementAccountLoadingIndicator';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import getPlaidOAuthReceivedRedirectURI from '@libs/getPlaidOAuthReceivedRedirectURI';
+import BankAccount from '@libs/models/BankAccount';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import shouldReopenOnfido from '@libs/shouldReopenOnfido';
+import withPolicy from '@pages/workspace/withPolicy';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import ACHContractStep from './ACHContractStep';
import BankAccountStep from './BankAccountStep';
import CompanyStep from './CompanyStep';
import ContinueBankAccountSetup from './ContinueBankAccountSetup';
-import RequestorStep from './RequestorStep';
-import ValidationStep from './ValidationStep';
-import ACHContractStep from './ACHContractStep';
import EnableStep from './EnableStep';
-import ROUTES from '../../ROUTES';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes';
-import withPolicy from '../workspace/withPolicy';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import shouldReopenOnfido from '../../libs/shouldReopenOnfido';
+import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
+import RequestorStep from './RequestorStep';
+import ValidationStep from './ValidationStep';
const propTypes = {
/** Plaid SDK token to use to initialize the widget */
@@ -340,6 +340,7 @@ class ReimbursementAccountPage extends React.Component {
}
if (subStep) {
BankAccounts.setBankAccountSubStep(null);
+ BankAccounts.setPlaidEvent(null);
} else {
Navigation.goBack(backTo);
}
@@ -396,8 +397,9 @@ class ReimbursementAccountPage extends React.Component {
);
}
-
- const isLoading = this.props.isLoadingReportData || this.props.account.isLoading || this.props.reimbursementAccount.isLoading;
+ const isLoading =
+ (this.props.isLoadingReportData || this.props.account.isLoading || this.props.reimbursementAccount.isLoading) &&
+ (!this.props.plaidCurrentEvent || this.props.plaidCurrentEvent === CONST.BANK_ACCOUNT.PLAID.EVENTS_NAME.EXIT);
// Prevent the full-page blocking offline view from being displayed for these steps if the device goes offline.
const shouldShowOfflineLoader = !(
@@ -534,6 +536,7 @@ class ReimbursementAccountPage extends React.Component {
ReimbursementAccountPage.propTypes = propTypes;
ReimbursementAccountPage.defaultProps = defaultProps;
+ReimbursementAccountPage.displayName = 'ReimbursementAccountPage';
export default compose(
withNetwork(),
@@ -550,6 +553,9 @@ export default compose(
plaidLinkToken: {
key: ONYXKEYS.PLAID_LINK_TOKEN,
},
+ plaidCurrentEvent: {
+ key: ONYXKEYS.PLAID_CURRENT_EVENT,
+ },
onfidoToken: {
key: ONYXKEYS.ONFIDO_TOKEN,
},
diff --git a/src/pages/ReimbursementAccount/RequestorOnfidoStep.js b/src/pages/ReimbursementAccount/RequestorOnfidoStep.js
index 474698c1e2b2..851869f9128d 100644
--- a/src/pages/ReimbursementAccount/RequestorOnfidoStep.js
+++ b/src/pages/ReimbursementAccount/RequestorOnfidoStep.js
@@ -1,18 +1,18 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {ScrollView} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import styles from '../../styles/styles';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import Onfido from '../../components/Onfido';
-import ONYXKEYS from '../../ONYXKEYS';
-import Growl from '../../libs/Growl';
-import CONST from '../../CONST';
-import FullPageOfflineBlockingView from '../../components/BlockingViews/FullPageOfflineBlockingView';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import useLocalize from '../../hooks/useLocalize';
+import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import Onfido from '@components/Onfido';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import Growl from '@libs/Growl';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
const propTypes = {
@@ -83,6 +83,7 @@ function RequestorOnfidoStep({onBackButtonPress, reimbursementAccount, onfidoTok
RequestorOnfidoStep.displayName = 'RequestorOnfidoStep';
RequestorOnfidoStep.propTypes = propTypes;
RequestorOnfidoStep.defaultProps = defaultProps;
+RequestorOnfidoStep.displayName = 'RequestorOnfidoStep';
export default withOnyx({
onfidoToken: {
diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js
index 86f1d5077eca..0eddb727d56d 100644
--- a/src/pages/ReimbursementAccount/RequestorStep.js
+++ b/src/pages/ReimbursementAccount/RequestorStep.js
@@ -1,22 +1,22 @@
+import _ from 'lodash';
+import PropTypes from 'prop-types';
import React, {useCallback, useMemo} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import _ from 'lodash';
-import styles from '../../styles/styles';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import CONST from '../../CONST';
-import TextLink from '../../components/TextLink';
-import CheckboxWithLabel from '../../components/CheckboxWithLabel';
-import Text from '../../components/Text';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import IdentityForm from './IdentityForm';
-import * as ValidationUtils from '../../libs/ValidationUtils';
-import ONYXKEYS from '../../ONYXKEYS';
-import RequestorOnfidoStep from './RequestorOnfidoStep';
-import Form from '../../components/Form';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import useLocalize from '../../hooks/useLocalize';
import {reimbursementAccountPropTypes} from './reimbursementAccountPropTypes';
+import RequestorOnfidoStep from './RequestorOnfidoStep';
const propTypes = {
onBackButtonPress: PropTypes.func.isRequired,
diff --git a/src/pages/ReimbursementAccount/StepPropTypes.js b/src/pages/ReimbursementAccount/StepPropTypes.js
index dc9734c6ecf7..04399230a1ab 100644
--- a/src/pages/ReimbursementAccount/StepPropTypes.js
+++ b/src/pages/ReimbursementAccount/StepPropTypes.js
@@ -1,7 +1,7 @@
import PropTypes from 'prop-types';
-import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
+import {withLocalizePropTypes} from '@components/withLocalize';
import reimbursementAccountDraftPropTypes from './ReimbursementAccountDraftPropTypes';
-import {withLocalizePropTypes} from '../../components/withLocalize';
+import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
export default {
/** The bank account currently in setup */
diff --git a/src/pages/ReimbursementAccount/ValidationStep.js b/src/pages/ReimbursementAccount/ValidationStep.js
index a63916db0784..5a0149aa3ba4 100644
--- a/src/pages/ReimbursementAccount/ValidationStep.js
+++ b/src/pages/ReimbursementAccount/ValidationStep.js
@@ -1,34 +1,34 @@
+import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import Str from 'expensify-common/lib/str';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import styles from '../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import * as Report from '../../libs/actions/Report';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import TextInput from '../../components/TextInput';
-import Text from '../../components/Text';
-import BankAccount from '../../libs/models/BankAccount';
-import TextLink from '../../components/TextLink';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as ValidationUtils from '../../libs/ValidationUtils';
+import Button from '@components/Button';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import MenuItem from '@components/MenuItem';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import BankAccount from '@libs/models/BankAccount';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import WorkspaceResetBankAccountModal from '@pages/workspace/WorkspaceResetBankAccountModal';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import Enable2FAPrompt from './Enable2FAPrompt';
import EnableStep from './EnableStep';
import * as ReimbursementAccountProps from './reimbursementAccountPropTypes';
-import Form from '../../components/Form';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import * as Illustrations from '../../components/Icon/Illustrations';
-import Section from '../../components/Section';
-import CONST from '../../CONST';
-import Button from '../../components/Button';
-import MenuItem from '../../components/MenuItem';
-import WorkspaceResetBankAccountModal from '../workspace/WorkspaceResetBankAccountModal';
-import Enable2FAPrompt from './Enable2FAPrompt';
-import ScreenWrapper from '../../components/ScreenWrapper';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/ReimbursementAccount/exampleCheckImage.js b/src/pages/ReimbursementAccount/exampleCheckImage.js
index 071a2eb08289..c3fdbdd3984c 100644
--- a/src/pages/ReimbursementAccount/exampleCheckImage.js
+++ b/src/pages/ReimbursementAccount/exampleCheckImage.js
@@ -1,6 +1,6 @@
-import exampleCheckImageEn from '../../../assets/images/example-check-image-en.png';
-import exampleCheckImageEs from '../../../assets/images/example-check-image-es.png';
-import CONST from '../../CONST';
+import exampleCheckImageEn from '@assets/images/example-check-image-en.png';
+import exampleCheckImageEs from '@assets/images/example-check-image-es.png';
+import CONST from '@src/CONST';
const images = {
[CONST.LOCALES.EN]: exampleCheckImageEn,
diff --git a/src/pages/ReimbursementAccount/reimbursementAccountPropTypes.js b/src/pages/ReimbursementAccount/reimbursementAccountPropTypes.js
index b1b5f30f7a76..8e94e2ad8f30 100644
--- a/src/pages/ReimbursementAccount/reimbursementAccountPropTypes.js
+++ b/src/pages/ReimbursementAccount/reimbursementAccountPropTypes.js
@@ -1,5 +1,5 @@
import PropTypes from 'prop-types';
-import BankAccount from '../../libs/models/BankAccount';
+import BankAccount from '@libs/models/BankAccount';
const reimbursementAccountPropTypes = PropTypes.shape({
/** Whether we are loading the data via the API */
diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js
index 71eff57a246d..ef28102cc144 100644
--- a/src/pages/ReportDetailsPage.js
+++ b/src/pages/ReportDetailsPage.js
@@ -1,34 +1,34 @@
-import React, {useMemo} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useMemo} from 'react';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import {View, ScrollView} from 'react-native';
-import RoomHeaderAvatars from '../components/RoomHeaderAvatars';
-import compose from '../libs/compose';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import ONYXKEYS from '../ONYXKEYS';
-import ScreenWrapper from '../components/ScreenWrapper';
-import Navigation from '../libs/Navigation/Navigation';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import styles from '../styles/styles';
-import DisplayNames from '../components/DisplayNames';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import * as ReportUtils from '../libs/ReportUtils';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import * as Report from '../libs/actions/Report';
-import participantPropTypes from '../components/participantPropTypes';
-import * as Expensicons from '../components/Icon/Expensicons';
-import ROUTES from '../ROUTES';
-import MenuItem from '../components/MenuItem';
-import Text from '../components/Text';
-import CONST from '../CONST';
-import reportPropTypes from './reportPropTypes';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import DisplayNames from '@components/DisplayNames';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import MultipleAvatars from '@components/MultipleAvatars';
+import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle';
+import participantPropTypes from '@components/participantPropTypes';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import RoomHeaderAvatars from '@components/RoomHeaderAvatars';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import withReportOrNotFound from './home/report/withReportOrNotFound';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
-import PressableWithoutFeedback from '../components/Pressable/PressableWithoutFeedback';
-import ParentNavigationSubtitle from '../components/ParentNavigationSubtitle';
-import MultipleAvatars from '../components/MultipleAvatars';
+import reportPropTypes from './reportPropTypes';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/ReportParticipantsPage.js b/src/pages/ReportParticipantsPage.js
index db56a8006e76..c2179c53126b 100755
--- a/src/pages/ReportParticipantsPage.js
+++ b/src/pages/ReportParticipantsPage.js
@@ -1,26 +1,26 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'underscore';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import styles from '../styles/styles';
-import ONYXKEYS from '../ONYXKEYS';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Navigation from '../libs/Navigation/Navigation';
-import ScreenWrapper from '../components/ScreenWrapper';
-import OptionsList from '../components/OptionsList';
-import ROUTES from '../ROUTES';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import OptionsList from '@components/OptionsList';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import withReportOrNotFound from './home/report/withReportOrNotFound';
import personalDetailsPropType from './personalDetailsPropType';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import compose from '../libs/compose';
-import * as ReportUtils from '../libs/ReportUtils';
import reportPropTypes from './reportPropTypes';
-import withReportOrNotFound from './home/report/withReportOrNotFound';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
-import CONST from '../CONST';
-import * as UserUtils from '../libs/UserUtils';
-import * as LocalePhoneNumber from '../libs/LocalePhoneNumber';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/ReportWelcomeMessagePage.js b/src/pages/ReportWelcomeMessagePage.js
index 48dd07090ef4..c4d91088eff0 100644
--- a/src/pages/ReportWelcomeMessagePage.js
+++ b/src/pages/ReportWelcomeMessagePage.js
@@ -1,28 +1,28 @@
-import React, {useCallback, useRef, useState} from 'react';
+import {useFocusEffect} from '@react-navigation/native';
+import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import PropTypes from 'prop-types';
-import {withOnyx} from 'react-native-onyx';
+import React, {useCallback, useRef, useState} from 'react';
import {View} from 'react-native';
-import ExpensiMark from 'expensify-common/lib/ExpensiMark';
-import {useFocusEffect} from '@react-navigation/native';
-import compose from '../libs/compose';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import styles from '../styles/styles';
-import reportPropTypes from './reportPropTypes';
+import {withOnyx} from 'react-native-onyx';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import updateMultilineInputRange from '@libs/UpdateMultilineInputRange';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import withReportOrNotFound from './home/report/withReportOrNotFound';
-import Text from '../components/Text';
-import TextInput from '../components/TextInput';
-import * as Report from '../libs/actions/Report';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
-import Form from '../components/Form';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import {policyPropTypes, policyDefaultProps} from './workspace/withPolicy';
-import ROUTES from '../ROUTES';
-import Navigation from '../libs/Navigation/Navigation';
-import updateMultilineInputRange from '../libs/UpdateMultilineInputRange';
+import reportPropTypes from './reportPropTypes';
+import {policyDefaultProps, policyPropTypes} from './workspace/withPolicy';
const propTypes = {
...withLocalizePropTypes,
@@ -46,7 +46,7 @@ const defaultProps = {
function ReportWelcomeMessagePage(props) {
const parser = new ExpensiMark();
- const [welcomeMessage, setWelcomeMessage] = useState(parser.htmlToMarkdown(props.report.welcomeMessage));
+ const [welcomeMessage, setWelcomeMessage] = useState(() => parser.htmlToMarkdown(props.report.welcomeMessage));
const welcomeMessageInputRef = useRef(null);
const focusTimeoutRef = useRef(null);
diff --git a/src/pages/RoomInvitePage.js b/src/pages/RoomInvitePage.js
index 5021ccdc42d7..71585fefbcd3 100644
--- a/src/pages/RoomInvitePage.js
+++ b/src/pages/RoomInvitePage.js
@@ -1,31 +1,31 @@
-import React, {useEffect, useMemo, useState, useCallback} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Navigation from '../libs/Navigation/Navigation';
-import styles from '../styles/styles';
-import compose from '../libs/compose';
-import ONYXKEYS from '../ONYXKEYS';
-import FormAlertWithSubmitButton from '../components/FormAlertWithSubmitButton';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import CONST from '../CONST';
-import {policyDefaultProps, policyPropTypes} from './workspace/withPolicy';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import useLocalize from '@hooks/useLocalize';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import withReportOrNotFound from './home/report/withReportOrNotFound';
-import reportPropTypes from './reportPropTypes';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
-import ROUTES from '../ROUTES';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import useLocalize from '../hooks/useLocalize';
-import SelectionList from '../components/SelectionList';
-import * as Report from '../libs/actions/Report';
-import * as ReportUtils from '../libs/ReportUtils';
-import Permissions from '../libs/Permissions';
import personalDetailsPropType from './personalDetailsPropType';
-import * as Browser from '../libs/Browser';
+import reportPropTypes from './reportPropTypes';
+import {policyDefaultProps, policyPropTypes} from './workspace/withPolicy';
const propTypes = {
/** Beta features list */
diff --git a/src/pages/RoomMembersPage.js b/src/pages/RoomMembersPage.js
index 3a6e3b6fd90f..a2599b3382d7 100644
--- a/src/pages/RoomMembersPage.js
+++ b/src/pages/RoomMembersPage.js
@@ -1,34 +1,34 @@
-import React, {useMemo, useState, useCallback, useEffect} from 'react';
-import _ from 'underscore';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import styles from '../styles/styles';
-import compose from '../libs/compose';
-import CONST from '../CONST';
-import ONYXKEYS from '../ONYXKEYS';
-import ROUTES from '../ROUTES';
-import Navigation from '../libs/Navigation/Navigation';
-import ScreenWrapper from '../components/ScreenWrapper';
-import FullPageNotFoundView from '../components/BlockingViews/FullPageNotFoundView';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import ConfirmModal from '../components/ConfirmModal';
-import Button from '../components/Button';
-import SelectionList from '../components/SelectionList';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../components/withWindowDimensions';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import Button from '@components/Button';
+import ConfirmModal from '@components/ConfirmModal';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import withReportOrNotFound from './home/report/withReportOrNotFound';
import personalDetailsPropType from './personalDetailsPropType';
import reportPropTypes from './reportPropTypes';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../components/withCurrentUserPersonalDetails';
-import * as PolicyUtils from '../libs/PolicyUtils';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import * as UserUtils from '../libs/UserUtils';
-import * as Report from '../libs/actions/Report';
-import * as ReportUtils from '../libs/ReportUtils';
-import Permissions from '../libs/Permissions';
-import Log from '../libs/Log';
-import * as Browser from '../libs/Browser';
const propTypes = {
/** All personal details asssociated with user */
diff --git a/src/pages/SearchPage.js b/src/pages/SearchPage.js
index 272fb30de858..f312ef2aa307 100755
--- a/src/pages/SearchPage.js
+++ b/src/pages/SearchPage.js
@@ -1,27 +1,27 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React, {Component} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import OptionsSelector from '../components/OptionsSelector';
-import * as OptionsListUtils from '../libs/OptionsListUtils';
-import * as ReportUtils from '../libs/ReportUtils';
-import ONYXKEYS from '../ONYXKEYS';
-import styles from '../styles/styles';
-import Navigation from '../libs/Navigation/Navigation';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../components/withWindowDimensions';
-import * as Report from '../libs/actions/Report';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import ScreenWrapper from '../components/ScreenWrapper';
-import Timing from '../libs/actions/Timing';
-import CONST from '../CONST';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import compose from '../libs/compose';
+import _ from 'underscore';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import OptionsSelector from '@components/OptionsSelector';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Performance from '@libs/Performance';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import Timing from '@userActions/Timing';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import personalDetailsPropType from './personalDetailsPropType';
import reportPropTypes from './reportPropTypes';
-import Performance from '../libs/Performance';
-import networkPropTypes from '../components/networkPropTypes';
-import {withNetwork} from '../components/OnyxProvider';
const propTypes = {
/* Onyx Props */
@@ -219,6 +219,7 @@ class SearchPage extends Component {
SearchPage.propTypes = propTypes;
SearchPage.defaultProps = defaultProps;
+SearchPage.displayName = 'SearchPage';
export default compose(
withLocalize,
diff --git a/src/pages/ShareCodePage.js b/src/pages/ShareCodePage.js
index e6d36ebc7070..b2bc32b381ce 100644
--- a/src/pages/ShareCodePage.js
+++ b/src/pages/ShareCodePage.js
@@ -1,35 +1,38 @@
+import PropTypes from 'prop-types';
import React from 'react';
-import {View, ScrollView} from 'react-native';
+import {ScrollView, View} from 'react-native';
import _ from 'underscore';
-import ScreenWrapper from '../components/ScreenWrapper';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
-import Navigation from '../libs/Navigation/Navigation';
-import withLocalize, {withLocalizePropTypes} from '../components/withLocalize';
-import QRShareWithDownload from '../components/QRShare/QRShareWithDownload';
-import compose from '../libs/compose';
+import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png';
+import ContextMenuItem from '@components/ContextMenuItem';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import QRShareWithDownload from '@components/QRShare/QRShareWithDownload';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withEnvironment from '@components/withEnvironment';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import Clipboard from '@libs/Clipboard';
+import compose from '@libs/compose';
+import getPlatform from '@libs/getPlatform';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as Url from '@libs/Url';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import reportPropTypes from './reportPropTypes';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../components/withCurrentUserPersonalDetails';
-import styles from '../styles/styles';
-import expensifyLogo from '../../assets/images/expensify-logo-round-transparent.png';
-import * as ReportUtils from '../libs/ReportUtils';
-import MenuItem from '../components/MenuItem';
-import Clipboard from '../libs/Clipboard';
-import * as Expensicons from '../components/Icon/Expensicons';
-import getPlatform from '../libs/getPlatform';
-import CONST from '../CONST';
-import ContextMenuItem from '../components/ContextMenuItem';
-import * as UserUtils from '../libs/UserUtils';
-import ROUTES from '../ROUTES';
-import withEnvironment, {environmentPropTypes} from '../components/withEnvironment';
-import * as Url from '../libs/Url';
const propTypes = {
/** The report currently being looked at */
report: reportPropTypes,
+ /** The string value representing the URL of the current environment */
+ environmentURL: PropTypes.string.isRequired,
+
...withLocalizePropTypes,
...withCurrentUserPersonalDetailsPropTypes,
- ...environmentPropTypes,
};
const defaultProps = {
@@ -122,5 +125,6 @@ class ShareCodePage extends React.Component {
ShareCodePage.propTypes = propTypes;
ShareCodePage.defaultProps = defaultProps;
+ShareCodePage.displayName = 'ShareCodePage';
export default compose(withEnvironment, withLocalize, withCurrentUserPersonalDetails)(ShareCodePage);
diff --git a/src/pages/TeachersUnite/ImTeacherPage.js b/src/pages/TeachersUnite/ImTeacherPage.js
index a938abf81b79..62cd4529611b 100644
--- a/src/pages/TeachersUnite/ImTeacherPage.js
+++ b/src/pages/TeachersUnite/ImTeacherPage.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as LoginUtils from '../../libs/LoginUtils';
+import * as LoginUtils from '@libs/LoginUtils';
+import ONYXKEYS from '@src/ONYXKEYS';
import ImTeacherUpdateEmailPage from './ImTeacherUpdateEmailPage';
import IntroSchoolPrincipalPage from './IntroSchoolPrincipalPage';
diff --git a/src/pages/TeachersUnite/ImTeacherUpdateEmailPage.js b/src/pages/TeachersUnite/ImTeacherUpdateEmailPage.js
index de83c71a01c7..5d7c1d960e3a 100644
--- a/src/pages/TeachersUnite/ImTeacherUpdateEmailPage.js
+++ b/src/pages/TeachersUnite/ImTeacherUpdateEmailPage.js
@@ -1,15 +1,15 @@
import React from 'react';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import ROUTES from '../../ROUTES';
-import Navigation from '../../libs/Navigation/Navigation';
-import FixedFooter from '../../components/FixedFooter';
-import styles from '../../styles/styles';
-import Button from '../../components/Button';
-import * as Illustrations from '../../components/Icon/Illustrations';
-import variables from '../../styles/variables';
-import useLocalize from '../../hooks/useLocalize';
-import BlockingView from '../../components/BlockingViews/BlockingView';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import Button from '@components/Button';
+import FixedFooter from '@components/FixedFooter';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Illustrations from '@components/Icon/Illustrations';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import ROUTES from '@src/ROUTES';
const propTypes = {};
diff --git a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.js b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.js
index 207ff0664053..25997fa9b307 100644
--- a/src/pages/TeachersUnite/IntroSchoolPrincipalPage.js
+++ b/src/pages/TeachersUnite/IntroSchoolPrincipalPage.js
@@ -1,24 +1,24 @@
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import Str from 'expensify-common/lib/str';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Form from '../../components/Form';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import TextInput from '../../components/TextInput';
-import Text from '../../components/Text';
-import styles from '../../styles/styles';
-import * as ErrorUtils from '../../libs/ErrorUtils';
-import ROUTES from '../../ROUTES';
-import Navigation from '../../libs/Navigation/Navigation';
-import TeachersUnite from '../../libs/actions/TeachersUnite';
-import useLocalize from '../../hooks/useLocalize';
-import * as ValidationUtils from '../../libs/ValidationUtils';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import TeachersUnite from '@userActions/TeachersUnite';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Login list for the user that is signed in */
diff --git a/src/pages/TeachersUnite/KnowATeacherPage.js b/src/pages/TeachersUnite/KnowATeacherPage.js
index f6506b96d3f2..d8dcc74faac0 100644
--- a/src/pages/TeachersUnite/KnowATeacherPage.js
+++ b/src/pages/TeachersUnite/KnowATeacherPage.js
@@ -1,25 +1,25 @@
-import React, {useCallback} from 'react';
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import Str from 'expensify-common/lib/str';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Form from '../../components/Form';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import * as LoginUtils from '../../libs/LoginUtils';
-import TextInput from '../../components/TextInput';
-import Text from '../../components/Text';
-import styles from '../../styles/styles';
-import * as ErrorUtils from '../../libs/ErrorUtils';
-import ROUTES from '../../ROUTES';
-import Navigation from '../../libs/Navigation/Navigation';
-import TeachersUnite from '../../libs/actions/TeachersUnite';
-import useLocalize from '../../hooks/useLocalize';
-import * as ValidationUtils from '../../libs/ValidationUtils';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import * as LoginUtils from '@libs/LoginUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import TeachersUnite from '@userActions/TeachersUnite';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Login list for the user that is signed in */
diff --git a/src/pages/TeachersUnite/SaveTheWorldPage.js b/src/pages/TeachersUnite/SaveTheWorldPage.js
index 5f252c960f8c..76e4c42294c1 100644
--- a/src/pages/TeachersUnite/SaveTheWorldPage.js
+++ b/src/pages/TeachersUnite/SaveTheWorldPage.js
@@ -1,20 +1,20 @@
+import _ from 'lodash';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import _ from 'lodash';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import SCREENS from '../../SCREENS';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import Text from '../../components/Text';
-import MenuItem from '../../components/MenuItem';
-import IllustratedHeaderPageLayout from '../../components/IllustratedHeaderPageLayout';
-import * as LottieAnimations from '../../components/LottieAnimations';
-import useLocalize from '../../hooks/useLocalize';
+import IllustratedHeaderPageLayout from '@components/IllustratedHeaderPageLayout';
+import * as LottieAnimations from '@components/LottieAnimations';
+import MenuItem from '@components/MenuItem';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
const propTypes = {
/** The list of this user's policies */
diff --git a/src/pages/UnlinkLoginPage.js b/src/pages/UnlinkLoginPage.js
index 67c073820bc0..ecaae0a84482 100644
--- a/src/pages/UnlinkLoginPage.js
+++ b/src/pages/UnlinkLoginPage.js
@@ -1,14 +1,14 @@
-import React, {useEffect} from 'react';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
-import {propTypes as validateLinkPropTypes, defaultProps as validateLinkDefaultProps} from './ValidateLoginPage/validateLinkPropTypes';
-import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator';
-import Navigation from '../libs/Navigation/Navigation';
-import * as Session from '../libs/actions/Session';
-import ROUTES from '../ROUTES';
-import usePrevious from '../hooks/usePrevious';
-import ONYXKEYS from '../ONYXKEYS';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import usePrevious from '@hooks/usePrevious';
+import Navigation from '@libs/Navigation/Navigation';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {defaultProps as validateLinkDefaultProps, propTypes as validateLinkPropTypes} from './ValidateLoginPage/validateLinkPropTypes';
const propTypes = {
/** The accountID and validateCode are passed via the URL */
diff --git a/src/pages/ValidateLoginPage/index.js b/src/pages/ValidateLoginPage/index.js
index 0af978172822..6939ee07f665 100644
--- a/src/pages/ValidateLoginPage/index.js
+++ b/src/pages/ValidateLoginPage/index.js
@@ -1,12 +1,12 @@
-import React, {useEffect} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import {propTypes as validateLinkPropTypes, defaultProps as validateLinkDefaultProps} from './validateLinkPropTypes';
-import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as Session from '../../libs/actions/Session';
-import Navigation from '../../libs/Navigation/Navigation';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import Navigation from '@libs/Navigation/Navigation';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps as validateLinkDefaultProps, propTypes as validateLinkPropTypes} from './validateLinkPropTypes';
const propTypes = {
/** The accountID and validateCode are passed via the URL */
diff --git a/src/pages/ValidateLoginPage/index.website.js b/src/pages/ValidateLoginPage/index.website.js
index 4ac12b3193f3..677abd70f6db 100644
--- a/src/pages/ValidateLoginPage/index.website.js
+++ b/src/pages/ValidateLoginPage/index.website.js
@@ -1,16 +1,16 @@
-import React, {useEffect} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import {propTypes as validateLinkPropTypes, defaultProps as validateLinkDefaultProps} from './validateLinkPropTypes';
-import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
-import ValidateCodeModal from '../../components/ValidateCode/ValidateCodeModal';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as Session from '../../libs/actions/Session';
-import ExpiredValidateCodeModal from '../../components/ValidateCode/ExpiredValidateCodeModal';
-import Navigation from '../../libs/Navigation/Navigation';
-import CONST from '../../CONST';
-import JustSignedInModal from '../../components/ValidateCode/JustSignedInModal';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import ExpiredValidateCodeModal from '@components/ValidateCode/ExpiredValidateCodeModal';
+import JustSignedInModal from '@components/ValidateCode/JustSignedInModal';
+import ValidateCodeModal from '@components/ValidateCode/ValidateCodeModal';
+import Navigation from '@libs/Navigation/Navigation';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps as validateLinkDefaultProps, propTypes as validateLinkPropTypes} from './validateLinkPropTypes';
const propTypes = {
/** The accountID and validateCode are passed via the URL */
diff --git a/src/pages/home/HeaderView.js b/src/pages/home/HeaderView.js
index e88f6cd0b756..36c48bd48fd2 100644
--- a/src/pages/home/HeaderView.js
+++ b/src/pages/home/HeaderView.js
@@ -1,40 +1,40 @@
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import React from 'react';
+import React, {memo} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import GoogleMeetIcon from '../../../assets/images/google-meet.svg';
-import ZoomIcon from '../../../assets/images/zoom-icon.svg';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
-import DisplayNames from '../../components/DisplayNames';
-import Icon from '../../components/Icon';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import MultipleAvatars from '../../components/MultipleAvatars';
-import ParentNavigationSubtitle from '../../components/ParentNavigationSubtitle';
-import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback';
-import SubscriptAvatar from '../../components/SubscriptAvatar';
-import TaskHeaderActionButton from '../../components/TaskHeaderActionButton';
-import Text from '../../components/Text';
-import ThreeDotsMenu from '../../components/ThreeDotsMenu';
-import Tooltip from '../../components/Tooltip';
-import participantPropTypes from '../../components/participantPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import * as HeaderUtils from '../../libs/HeaderUtils';
-import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as Link from '../../libs/actions/Link';
-import * as Report from '../../libs/actions/Report';
-import * as Task from '../../libs/actions/Task';
-import compose from '../../libs/compose';
-import * as Session from '../../libs/actions/Session';
-import styles from '../../styles/styles';
-import themeColors from '../../styles/themes/default';
-import reportPropTypes from '../reportPropTypes';
-import reportWithoutHasDraftSelector from '../../libs/OnyxSelectors/reportWithoutHasDraftSelector';
+import GoogleMeetIcon from '@assets/images/google-meet.svg';
+import ZoomIcon from '@assets/images/zoom-icon.svg';
+import DisplayNames from '@components/DisplayNames';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MultipleAvatars from '@components/MultipleAvatars';
+import ParentNavigationSubtitle from '@components/ParentNavigationSubtitle';
+import participantPropTypes from '@components/participantPropTypes';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import SubscriptAvatar from '@components/SubscriptAvatar';
+import TaskHeaderActionButton from '@components/TaskHeaderActionButton';
+import Text from '@components/Text';
+import ThreeDotsMenu from '@components/ThreeDotsMenu';
+import Tooltip from '@components/Tooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import * as HeaderUtils from '@libs/HeaderUtils';
+import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as Link from '@userActions/Link';
+import * as Report from '@userActions/Report';
+import * as Session from '@userActions/Session';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Toggles the navigationMenu open and closed */
@@ -271,21 +271,23 @@ HeaderView.propTypes = propTypes;
HeaderView.displayName = 'HeaderView';
HeaderView.defaultProps = defaultProps;
-export default compose(
- withWindowDimensions,
- withLocalize,
- withOnyx({
- guideCalendarLink: {
- key: ONYXKEYS.ACCOUNT,
- selector: (account) => (account && account.guideCalendarLink) || null,
- initialValue: null,
- },
- parentReport: {
- key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID || report.reportID}`,
- selector: reportWithoutHasDraftSelector,
- },
- session: {
- key: ONYXKEYS.SESSION,
- },
- }),
-)(HeaderView);
+export default memo(
+ compose(
+ withWindowDimensions,
+ withLocalize,
+ withOnyx({
+ guideCalendarLink: {
+ key: ONYXKEYS.ACCOUNT,
+ selector: (account) => (account && account.guideCalendarLink) || null,
+ initialValue: null,
+ },
+ parentReport: {
+ key: ({report}) => `${ONYXKEYS.COLLECTION.REPORT}${report.parentReportID || report.reportID}`,
+ selector: reportWithoutHasDraftSelector,
+ },
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ }),
+ )(HeaderView),
+);
diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js
index 32a14303e9a7..2ccc5246da81 100644
--- a/src/pages/home/ReportScreen.js
+++ b/src/pages/home/ReportScreen.js
@@ -1,45 +1,45 @@
-import React, {useRef, useState, useEffect, useMemo, useCallback} from 'react';
-import {withOnyx} from 'react-native-onyx';
import {useFocusEffect} from '@react-navigation/native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
-import lodashGet from 'lodash/get';
+import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import ScreenWrapper from '../../components/ScreenWrapper';
+import Banner from '@components/Banner';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import DragAndDropProvider from '@components/DragAndDrop/Provider';
+import MoneyReportHeader from '@components/MoneyReportHeader';
+import MoneyRequestHeader from '@components/MoneyRequestHeader';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TaskHeaderActionButton from '@components/TaskHeaderActionButton';
+import withCurrentReportID, {withCurrentReportIDDefaultProps, withCurrentReportIDPropTypes} from '@components/withCurrentReportID';
+import withViewportOffsetTop from '@components/withViewportOffsetTop';
+import useLocalize from '@hooks/useLocalize';
+import usePrevious from '@hooks/usePrevious';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import compose from '@libs/compose';
+import getIsReportFullyVisible from '@libs/getIsReportFullyVisible';
+import Navigation from '@libs/Navigation/Navigation';
+import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import Visibility from '@libs/Visibility';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportMetadataPropTypes from '@pages/reportMetadataPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as ComposerActions from '@userActions/Composer';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import HeaderView from './HeaderView';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import * as Report from '../../libs/actions/Report';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as ReportUtils from '../../libs/ReportUtils';
-import ReportActionsView from './report/ReportActionsView';
-import ReportActionsSkeletonView from '../../components/ReportActionsSkeletonView';
import reportActionPropTypes from './report/reportActionPropTypes';
-import compose from '../../libs/compose';
-import Visibility from '../../libs/Visibility';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import useLocalize from '../../hooks/useLocalize';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
+import ReportActionsView from './report/ReportActionsView';
import ReportFooter from './report/ReportFooter';
-import Banner from '../../components/Banner';
-import reportPropTypes from '../reportPropTypes';
-import reportMetadataPropTypes from '../reportMetadataPropTypes';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import withViewportOffsetTop from '../../components/withViewportOffsetTop';
-import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
-import personalDetailsPropType from '../personalDetailsPropType';
-import getIsReportFullyVisible from '../../libs/getIsReportFullyVisible';
-import MoneyRequestHeader from '../../components/MoneyRequestHeader';
-import MoneyReportHeader from '../../components/MoneyReportHeader';
-import * as ComposerActions from '../../libs/actions/Composer';
import {ActionListContext, ReactionListContext} from './ReportScreenContext';
-import TaskHeaderActionButton from '../../components/TaskHeaderActionButton';
-import DragAndDropProvider from '../../components/DragAndDrop/Provider';
-import usePrevious from '../../hooks/usePrevious';
-import CONST from '../../CONST';
-import withCurrentReportID, {withCurrentReportIDPropTypes, withCurrentReportIDDefaultProps} from '../../components/withCurrentReportID';
-import reportWithoutHasDraftSelector from '../../libs/OnyxSelectors/reportWithoutHasDraftSelector';
const propTypes = {
/** Navigation route context info provided by react navigation */
@@ -106,8 +106,9 @@ const defaultProps = {
hasOutstandingIOU: false,
},
reportMetadata: {
- isLoadingReportActions: true,
- isLoadingMoreReportActions: false,
+ isLoadingInitialReportActions: true,
+ isLoadingOlderReportActions: false,
+ isLoadingNewerReportActions: false,
},
isComposerFullSize: false,
betas: [],
@@ -165,7 +166,7 @@ function ReportScreen({
const screenWrapperStyle = [styles.appContent, styles.flex1, {marginTop: viewportOffsetTop}];
// There are no reportActions at all to display and we are still in the process of loading the next set of actions.
- const isLoadingInitialReportActions = _.isEmpty(reportActions) && reportMetadata.isLoadingReportActions;
+ const isLoadingInitialReportActions = _.isEmpty(reportActions) && reportMetadata.isLoadingInitialReportActions;
const isOptimisticDelete = lodashGet(report, 'statusNum') === CONST.REPORT.STATUS.CLOSED;
@@ -181,10 +182,14 @@ function ReportScreen({
const isTopMostReportId = currentReportID === getReportID(route);
const didSubscribeToReportLeavingEvents = useRef(false);
+ const goBack = useCallback(() => {
+ Navigation.goBack(ROUTES.HOME, false, true);
+ }, []);
+
let headerView = (
Navigation.goBack(ROUTES.HOME, false, true)}
+ onNavigationMenuButtonClicked={goBack}
personalDetails={personalDetails}
report={report}
/>
@@ -260,6 +265,13 @@ function ReportScreen({
const onSubmitComment = useCallback(
(text) => {
Report.addComment(getReportID(route), text);
+
+ // We need to scroll to the bottom of the list after the comment is added
+ const refID = setTimeout(() => {
+ flatListRef.current.scrollToOffset({animated: false, offset: 0});
+ }, 10);
+
+ return () => clearTimeout(refID);
},
[route],
);
@@ -372,7 +384,7 @@ function ReportScreen({
// eslint-disable-next-line rulesdir/no-negated-variables
const shouldShowNotFoundPage = useMemo(
- () => (!firstRenderRef.current && !report.reportID && !isOptimisticDelete && !reportMetadata.isLoadingReportActions && !isLoading && !userLeavingStatus) || shouldHideReport,
+ () => (!firstRenderRef.current && !report.reportID && !isOptimisticDelete && !reportMetadata.isLoadingInitialReportActions && !isLoading && !userLeavingStatus) || shouldHideReport,
[report, reportMetadata, isLoading, shouldHideReport, isOptimisticDelete, userLeavingStatus],
);
@@ -428,8 +440,9 @@ function ReportScreen({
@@ -488,8 +501,9 @@ export default compose(
reportMetadata: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${getReportID(route)}`,
initialValue: {
- isLoadingReportActions: true,
- isLoadingMoreReportActions: false,
+ isLoadingInitialReportActions: true,
+ isLoadingOlderReportActions: false,
+ isLoadingNewerReportActions: false,
},
},
isComposerFullSize: {
diff --git a/src/pages/home/ReportScreenContext.js b/src/pages/home/ReportScreenContext.js
deleted file mode 100644
index 1e8d30cf7585..000000000000
--- a/src/pages/home/ReportScreenContext.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import {createContext} from 'react';
-
-const ActionListContext = createContext();
-const ReactionListContext = createContext();
-
-export {ActionListContext, ReactionListContext};
diff --git a/src/pages/home/ReportScreenContext.ts b/src/pages/home/ReportScreenContext.ts
new file mode 100644
index 000000000000..ab85c9e3afb9
--- /dev/null
+++ b/src/pages/home/ReportScreenContext.ts
@@ -0,0 +1,17 @@
+import {createContext, RefObject} from 'react';
+import {FlatList, GestureResponderEvent} from 'react-native';
+
+type ReactionListRef = {
+ showReactionList: (event: GestureResponderEvent | undefined, reactionListAnchor: Element, emojiName: string, reportActionID: string) => void;
+ hideReactionList: () => void;
+ isActiveReportAction: (actionID: number | string) => boolean;
+};
+
+type ActionListContextType = RefObject> | null;
+type ReactionListContextType = RefObject | null;
+
+const ActionListContext = createContext(null);
+const ReactionListContext = createContext(null);
+
+export {ActionListContext, ReactionListContext};
+export type {ReactionListRef, ActionListContextType, ReactionListContextType};
diff --git a/src/pages/home/report/AnimatedEmptyStateBackground.js b/src/pages/home/report/AnimatedEmptyStateBackground.js
index 6d85e4d7fc85..6091347a24a2 100644
--- a/src/pages/home/report/AnimatedEmptyStateBackground.js
+++ b/src/pages/home/report/AnimatedEmptyStateBackground.js
@@ -1,11 +1,11 @@
import React from 'react';
import Animated, {SensorType, useAnimatedSensor, useAnimatedStyle, useSharedValue, withSpring} from 'react-native-reanimated';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
-import * as NumberUtils from '../../../libs/NumberUtils';
-import EmptyStateBackgroundImage from '../../../../assets/images/empty-state_background-fade.png';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import variables from '../../../styles/variables';
-import CONST from '../../../CONST';
+import EmptyStateBackgroundImage from '@assets/images/empty-state_background-fade.png';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as NumberUtils from '@libs/NumberUtils';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
const IMAGE_OFFSET_Y = 75;
diff --git a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js
index 91fe38784e9c..18351f86a400 100755
--- a/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js
+++ b/src/pages/home/report/ContextMenu/BaseReportActionContextMenu.js
@@ -1,24 +1,24 @@
-import React, {useRef, useMemo, useState, memo} from 'react';
-import {InteractionManager, View} from 'react-native';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
import PropTypes from 'prop-types';
+import React, {memo, useMemo, useRef, useState} from 'react';
+import {InteractionManager, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import getReportActionContextMenuStyles from '../../../../styles/getReportActionContextMenuStyles';
-import ContextMenuItem from '../../../../components/ContextMenuItem';
-import {propTypes as genericReportActionContextMenuPropTypes, defaultProps as GenericReportActionContextMenuDefaultProps} from './genericReportActionContextMenuPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
+import _ from 'underscore';
+import ContextMenuItem from '@components/ContextMenuItem';
+import {withBetas} from '@components/OnyxProvider';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager';
+import useKeyboardShortcut from '@hooks/useKeyboardShortcut';
+import useNetwork from '@hooks/useNetwork';
+import compose from '@libs/compose';
+import getReportActionContextMenuStyles from '@styles/getReportActionContextMenuStyles';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import ContextMenuActions, {CONTEXT_MENU_TYPES} from './ContextMenuActions';
-import compose from '../../../../libs/compose';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../../components/withWindowDimensions';
-import {withBetas} from '../../../../components/OnyxProvider';
-import * as Session from '../../../../libs/actions/Session';
+import {defaultProps as GenericReportActionContextMenuDefaultProps, propTypes as genericReportActionContextMenuPropTypes} from './genericReportActionContextMenuPropTypes';
import {hideContextMenu} from './ReportActionContextMenu';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import CONST from '../../../../CONST';
-import useArrowKeyFocusManager from '../../../../hooks/useArrowKeyFocusManager';
-import useKeyboardShortcut from '../../../../hooks/useKeyboardShortcut';
-import useNetwork from '../../../../hooks/useNetwork';
const propTypes = {
/** String representing the context menu type [LINK, REPORT_ACTION] which controls context menu choices */
diff --git a/src/pages/home/report/ContextMenu/ContextMenuActions.js b/src/pages/home/report/ContextMenu/ContextMenuActions.js
index 6c9970bde796..5a1266d15a42 100644
--- a/src/pages/home/report/ContextMenu/ContextMenuActions.js
+++ b/src/pages/home/report/ContextMenu/ContextMenuActions.js
@@ -1,27 +1,27 @@
-import React from 'react';
-import _ from 'underscore';
import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import lodashGet from 'lodash/get';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import * as Report from '../../../../libs/actions/Report';
-import * as Download from '../../../../libs/actions/Download';
-import Clipboard from '../../../../libs/Clipboard';
-import * as ReportUtils from '../../../../libs/ReportUtils';
-import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils';
-import * as PersonalDetailsUtils from '../../../../libs/PersonalDetailsUtils';
-import ReportActionComposeFocusManager from '../../../../libs/ReportActionComposeFocusManager';
-import {hideContextMenu, showDeleteModal, clearActiveReportAction} from './ReportActionContextMenu';
-import CONST from '../../../../CONST';
-import getAttachmentDetails from '../../../../libs/fileDownload/getAttachmentDetails';
-import fileDownload from '../../../../libs/fileDownload';
-import addEncryptedAuthTokenToURL from '../../../../libs/addEncryptedAuthTokenToURL';
-import * as Environment from '../../../../libs/Environment/Environment';
-import Permissions from '../../../../libs/Permissions';
-import QuickEmojiReactions from '../../../../components/Reactions/QuickEmojiReactions';
-import MiniQuickEmojiReactions from '../../../../components/Reactions/MiniQuickEmojiReactions';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ROUTES from '../../../../ROUTES';
-import * as Task from '../../../../libs/actions/Task';
+import React from 'react';
+import _ from 'underscore';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MiniQuickEmojiReactions from '@components/Reactions/MiniQuickEmojiReactions';
+import QuickEmojiReactions from '@components/Reactions/QuickEmojiReactions';
+import addEncryptedAuthTokenToURL from '@libs/addEncryptedAuthTokenToURL';
+import Clipboard from '@libs/Clipboard';
+import * as Environment from '@libs/Environment/Environment';
+import fileDownload from '@libs/fileDownload';
+import getAttachmentDetails from '@libs/fileDownload/getAttachmentDetails';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as Download from '@userActions/Download';
+import * as Report from '@userActions/Report';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
+import {clearActiveReportAction, hideContextMenu, showDeleteModal} from './ReportActionContextMenu';
/**
* Gets the HTML version of the message in an action.
@@ -125,10 +125,12 @@ export default [
if (type !== CONTEXT_MENU_TYPES.REPORT_ACTION) {
return false;
}
- const isCommentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && !ReportUtils.isThreadFirstChat(reportAction, reportID);
+ const isCommentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT;
const isReportPreviewAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW;
const isIOUAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !ReportActionsUtils.isSplitBillAction(reportAction);
- return isCommentAction || isReportPreviewAction || isIOUAction;
+ const isModifiedExpenseAction = ReportActionsUtils.isModifiedExpenseAction(reportAction);
+ const isTaskAction = ReportActionsUtils.isTaskAction(reportAction);
+ return (isCommentAction || isReportPreviewAction || isIOUAction || isModifiedExpenseAction || isTaskAction) && !ReportUtils.isThreadFirstChat(reportAction, reportID);
},
onPress: (closePopover, {reportAction, reportID}) => {
if (closePopover) {
@@ -143,6 +145,83 @@ export default [
},
getDescription: () => {},
},
+ {
+ isAnonymousAction: false,
+ textTranslateKey: 'reportActionContextMenu.subscribeToThread',
+ icon: Expensicons.Bell,
+ successTextTranslateKey: '',
+ successIcon: null,
+ shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID) => {
+ let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', '');
+ if (!childReportNotificationPreference) {
+ const isActionCreator = ReportUtils.isActionCreator(reportAction);
+ childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
+ }
+ const subscribed = childReportNotificationPreference !== 'hidden';
+ const isCommentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && !ReportUtils.isThreadFirstChat(reportAction, reportID);
+ const isReportPreviewAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW;
+ const isIOUAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !ReportActionsUtils.isSplitBillAction(reportAction);
+ return !subscribed && (isCommentAction || isReportPreviewAction || isIOUAction);
+ },
+ onPress: (closePopover, {reportAction, reportID}) => {
+ let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', '');
+ if (!childReportNotificationPreference) {
+ const isActionCreator = ReportUtils.isActionCreator(reportAction);
+ childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
+ }
+ if (closePopover) {
+ hideContextMenu(false, () => {
+ ReportActionComposeFocusManager.focus();
+ Report.toggleSubscribeToChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID, childReportNotificationPreference);
+ });
+ return;
+ }
+
+ ReportActionComposeFocusManager.focus();
+ Report.toggleSubscribeToChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID, childReportNotificationPreference);
+ },
+ getDescription: () => {},
+ },
+ {
+ isAnonymousAction: false,
+ textTranslateKey: 'reportActionContextMenu.unsubscribeFromThread',
+ icon: Expensicons.BellSlash,
+ successTextTranslateKey: '',
+ successIcon: null,
+ shouldShow: (type, reportAction, isArchivedRoom, betas, anchor, isChronosReport, reportID) => {
+ let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', '');
+ if (!childReportNotificationPreference) {
+ const isActionCreator = ReportUtils.isActionCreator(reportAction);
+ childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
+ }
+ const subscribed = childReportNotificationPreference !== 'hidden';
+ if (type !== CONTEXT_MENU_TYPES.REPORT_ACTION) {
+ return false;
+ }
+ const isCommentAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT && !ReportUtils.isThreadFirstChat(reportAction, reportID);
+ const isReportPreviewAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.REPORTPREVIEW;
+ const isIOUAction = reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU && !ReportActionsUtils.isSplitBillAction(reportAction);
+ return subscribed && (isCommentAction || isReportPreviewAction || isIOUAction);
+ },
+ onPress: (closePopover, {reportAction, reportID}) => {
+ let childReportNotificationPreference = lodashGet(reportAction, 'childReportNotificationPreference', '');
+ if (!childReportNotificationPreference) {
+ const isActionCreator = ReportUtils.isActionCreator(reportAction);
+ childReportNotificationPreference = isActionCreator ? CONST.REPORT.NOTIFICATION_PREFERENCE.ALWAYS : CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN;
+ }
+ if (closePopover) {
+ hideContextMenu(false, () => {
+ ReportActionComposeFocusManager.focus();
+ Report.toggleSubscribeToChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID, childReportNotificationPreference);
+ });
+ return;
+ }
+
+ ReportActionComposeFocusManager.focus();
+ Report.toggleSubscribeToChildReport(lodashGet(reportAction, 'childReportID', '0'), reportAction, reportID, childReportNotificationPreference);
+ },
+ getDescription: () => {},
+ },
{
isAnonymousAction: true,
textTranslateKey: 'reportActionContextMenu.copyURLToClipboard',
diff --git a/src/pages/home/report/ContextMenu/MiniReportActionContextMenu/index.js b/src/pages/home/report/ContextMenu/MiniReportActionContextMenu/index.js
index 60ed7ed989b0..ef28a2690af4 100644
--- a/src/pages/home/report/ContextMenu/MiniReportActionContextMenu/index.js
+++ b/src/pages/home/report/ContextMenu/MiniReportActionContextMenu/index.js
@@ -1,11 +1,14 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import {propTypes as genericReportActionContextMenuPropTypes, defaultProps as GenericReportActionContextMenuDefaultProps} from '../genericReportActionContextMenuPropTypes';
-import * as StyleUtils from '../../../../../styles/StyleUtils';
-import BaseReportActionContextMenu from '../BaseReportActionContextMenu';
-import CONST from '../../../../../CONST';
+import _ from 'underscore';
+import BaseReportActionContextMenu from '@pages/home/report/ContextMenu/BaseReportActionContextMenu';
+import {
+ defaultProps as GenericReportActionContextMenuDefaultProps,
+ propTypes as genericReportActionContextMenuPropTypes,
+} from '@pages/home/report/ContextMenu/genericReportActionContextMenuPropTypes';
+import * as StyleUtils from '@styles/StyleUtils';
+import CONST from '@src/CONST';
const propTypes = {
..._.omit(genericReportActionContextMenuPropTypes, ['isMini']),
diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js
index e987eff4c7e8..7f60b9d9b4d5 100644
--- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js
+++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js
@@ -1,13 +1,13 @@
-import React, {forwardRef, useEffect, useState, useRef, useImperativeHandle, useCallback} from 'react';
+import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
import {Dimensions} from 'react-native';
import _ from 'underscore';
-import * as Report from '../../../../libs/actions/Report';
-import PopoverWithMeasuredContent from '../../../../components/PopoverWithMeasuredContent';
+import ConfirmModal from '@components/ConfirmModal';
+import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent';
+import useLocalize from '@hooks/useLocalize';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as IOU from '@userActions/IOU';
+import * as Report from '@userActions/Report';
import BaseReportActionContextMenu from './BaseReportActionContextMenu';
-import ConfirmModal from '../../../../components/ConfirmModal';
-import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils';
-import * as IOU from '../../../../libs/actions/IOU';
-import useLocalize from '../../../../hooks/useLocalize';
function PopoverReportActionContextMenu(_props, ref) {
const {translate} = useLocalize();
@@ -238,7 +238,7 @@ function PopoverReportActionContextMenu(_props, ref) {
Report.deleteReportComment(reportIDRef.current, reportActionRef.current);
}
setIsDeleteCommentConfirmModalVisible(false);
- }, [reportActionRef]);
+ }, []);
const hideDeleteModal = () => {
callbackWhenDeleteModalHide.current = () => (onCancelDeleteModal.current = runAndResetCallback(onCancelDeleteModal.current));
diff --git a/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.android.js b/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.android.js
index c533a9ca1e3b..93437393a5c5 100644
--- a/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.android.js
+++ b/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.android.js
@@ -1,6 +1,6 @@
import React from 'react';
-import {View, Animated} from 'react-native';
-import styles from '../../../../../styles/styles';
+import {Animated, View} from 'react-native';
+import styles from '@styles/styles';
import floatingMessageCounterContainerPropTypes from './floatingMessageCounterContainerPropTypes';
function FloatingMessageCounterContainer(props) {
diff --git a/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.js b/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.js
index 134312aa7af5..2137fa07b573 100644
--- a/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.js
+++ b/src/pages/home/report/FloatingMessageCounter/FloatingMessageCounterContainer/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import {Animated} from 'react-native';
-import styles from '../../../../../styles/styles';
+import styles from '@styles/styles';
import floatingMessageCounterContainerPropTypes from './floatingMessageCounterContainerPropTypes';
function FloatingMessageCounterContainer(props) {
diff --git a/src/pages/home/report/FloatingMessageCounter/index.js b/src/pages/home/report/FloatingMessageCounter/index.js
index a4e2d25d9490..a2a0e9a3b21b 100644
--- a/src/pages/home/report/FloatingMessageCounter/index.js
+++ b/src/pages/home/report/FloatingMessageCounter/index.js
@@ -1,16 +1,16 @@
-import React, {useEffect, useMemo, useCallback} from 'react';
-import {Animated, View} from 'react-native';
import PropTypes from 'prop-types';
-import CONST from '../../../../CONST';
-import styles from '../../../../styles/styles';
-import Button from '../../../../components/Button';
-import Text from '../../../../components/Text';
-import Icon from '../../../../components/Icon';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import themeColors from '../../../../styles/themes/default';
-import useLocalize from '../../../../hooks/useLocalize';
+import React, {useCallback, useEffect, useMemo} from 'react';
+import {Animated, View} from 'react-native';
+import Button from '@components/Button';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useNativeDriver from '@libs/useNativeDriver';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
import FloatingMessageCounterContainer from './FloatingMessageCounterContainer';
-import useNativeDriver from '../../../../libs/useNativeDriver';
const propTypes = {
/** Whether the New Messages indicator is active */
diff --git a/src/pages/home/report/LinkPreviewer.js b/src/pages/home/report/LinkPreviewer.js
index 4fcbb0dc0569..ebdab22a1c1e 100644
--- a/src/pages/home/report/LinkPreviewer.js
+++ b/src/pages/home/report/LinkPreviewer.js
@@ -1,14 +1,14 @@
-import React from 'react';
-import {View, Image} from 'react-native';
+import {uniqBy} from 'lodash';
import PropTypes from 'prop-types';
+import React from 'react';
+import {Image, View} from 'react-native';
import _ from 'underscore';
-import {uniqBy} from 'lodash';
-import Text from '../../../components/Text';
-import TextLink from '../../../components/TextLink';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import styles from '../../../styles/styles';
-import variables from '../../../styles/variables';
-import themeColors from '../../../styles/themes/default';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
const IMAGE_TYPES = ['jpg', 'jpeg', 'png'];
const MAX_IMAGE_HEIGHT = 180;
diff --git a/src/pages/home/report/ListBoundaryLoader/ListBoundaryLoader.js b/src/pages/home/report/ListBoundaryLoader/ListBoundaryLoader.js
new file mode 100644
index 000000000000..861f6201a53f
--- /dev/null
+++ b/src/pages/home/report/ListBoundaryLoader/ListBoundaryLoader.js
@@ -0,0 +1,73 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import {ActivityIndicator, View} from 'react-native';
+import ReportActionsSkeletonView from '@components/ReportActionsSkeletonView';
+import useNetwork from '@hooks/useNetwork';
+import styles, {stylesGenerator} from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+
+const propTypes = {
+ /** type of rendered loader. Can be 'header' or 'footer' */
+ type: PropTypes.oneOf([CONST.LIST_COMPONENTS.HEADER, CONST.LIST_COMPONENTS.FOOTER]).isRequired,
+
+ /** Shows if we call fetching older report action */
+ isLoadingOlderReportActions: PropTypes.bool,
+
+ /* Shows if we call initial loading of report action */
+ isLoadingInitialReportActions: PropTypes.bool,
+
+ /** Shows if we call fetching newer report action */
+ isLoadingNewerReportActions: PropTypes.bool,
+
+ /** Name of the last report action */
+ lastReportActionName: PropTypes.string,
+};
+
+const defaultProps = {
+ isLoadingOlderReportActions: false,
+ isLoadingInitialReportActions: false,
+ isLoadingNewerReportActions: false,
+ lastReportActionName: '',
+};
+
+function ListBoundaryLoader({type, isLoadingOlderReportActions, isLoadingInitialReportActions, lastReportActionName, isLoadingNewerReportActions}) {
+ const {isOffline} = useNetwork();
+
+ // we use two different loading components for header and footer to reduce the jumping effect when you scrolling to the newer reports
+ if (type === CONST.LIST_COMPONENTS.FOOTER) {
+ if (isLoadingOlderReportActions) {
+ return ;
+ }
+
+ // Make sure the oldest report action loaded is not the first. This is so we do not show the
+ // skeleton view above the created action in a newly generated optimistic chat or one with not
+ // that many comments.
+ if (isLoadingInitialReportActions && lastReportActionName !== CONST.REPORT.ACTIONS.TYPE.CREATED) {
+ return (
+
+ );
+ }
+ }
+ if (type === CONST.LIST_COMPONENTS.HEADER && isLoadingNewerReportActions) {
+ // applied for a header of the list, i.e. when you scroll to the bottom of the list
+ // the styles for android and the rest components are different that's why we use two different components
+ return (
+
+
+
+ );
+ }
+}
+
+ListBoundaryLoader.propTypes = propTypes;
+ListBoundaryLoader.defaultProps = defaultProps;
+ListBoundaryLoader.displayName = 'ListBoundaryLoader';
+
+export default ListBoundaryLoader;
diff --git a/src/pages/home/report/ParticipantLocalTime.js b/src/pages/home/report/ParticipantLocalTime.js
index 058346287b11..17f87f0391ea 100644
--- a/src/pages/home/report/ParticipantLocalTime.js
+++ b/src/pages/home/report/ParticipantLocalTime.js
@@ -1,13 +1,13 @@
-import React, {useState, useEffect} from 'react';
-import {View} from 'react-native';
import lodashGet from 'lodash/get';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import participantPropTypes from '../../../components/participantPropTypes';
-import Text from '../../../components/Text';
-import Timers from '../../../libs/Timers';
-import CONST from '../../../CONST';
-import DateUtils from '../../../libs/DateUtils';
+import React, {useEffect, useState} from 'react';
+import {View} from 'react-native';
+import participantPropTypes from '@components/participantPropTypes';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import DateUtils from '@libs/DateUtils';
+import Timers from '@libs/Timers';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** Personal details of the participant */
diff --git a/src/pages/home/report/ReactionList/BaseReactionList.js b/src/pages/home/report/ReactionList/BaseReactionList.js
index b082ca510edd..bd1ed436ceaa 100755
--- a/src/pages/home/report/ReactionList/BaseReactionList.js
+++ b/src/pages/home/report/ReactionList/BaseReactionList.js
@@ -1,19 +1,19 @@
/* eslint-disable rulesdir/onyx-props-must-have-default */
+import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
import React from 'react';
import {FlatList} from 'react-native';
-import PropTypes from 'prop-types';
-import Str from 'expensify-common/lib/str';
-import styles from '../../../../styles/styles';
+import OptionRow from '@components/OptionRow';
+import participantPropTypes from '@components/participantPropTypes';
+import withWindowDimensions from '@components/withWindowDimensions';
+import Navigation from '@libs/Navigation/Navigation';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import HeaderReactionList from './HeaderReactionList';
-import * as UserUtils from '../../../../libs/UserUtils';
-import CONST from '../../../../CONST';
-import participantPropTypes from '../../../../components/participantPropTypes';
import reactionPropTypes from './reactionPropTypes';
-import OptionRow from '../../../../components/OptionRow';
-import variables from '../../../../styles/variables';
-import withWindowDimensions from '../../../../components/withWindowDimensions';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ROUTES from '../../../../ROUTES';
const propTypes = {
/**
diff --git a/src/pages/home/report/ReactionList/HeaderReactionList.js b/src/pages/home/report/ReactionList/HeaderReactionList.js
index 00611ca12409..49d61f05b191 100644
--- a/src/pages/home/report/ReactionList/HeaderReactionList.js
+++ b/src/pages/home/report/ReactionList/HeaderReactionList.js
@@ -1,13 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import Text from '../../../../components/Text';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../../components/withWindowDimensions';
-import compose from '../../../../libs/compose';
-import * as EmojiUtils from '../../../../libs/EmojiUtils';
-import * as StyleUtils from '../../../../styles/StyleUtils';
-import styles from '../../../../styles/styles';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
import reactionPropTypes from './reactionPropTypes';
const propTypes = {
diff --git a/src/pages/home/report/ReactionList/PopoverReactionList/BasePopoverReactionList.js b/src/pages/home/report/ReactionList/PopoverReactionList/BasePopoverReactionList.js
index 32433cc80ca5..a06ed18de957 100644
--- a/src/pages/home/report/ReactionList/PopoverReactionList/BasePopoverReactionList.js
+++ b/src/pages/home/report/ReactionList/PopoverReactionList/BasePopoverReactionList.js
@@ -1,19 +1,19 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {Dimensions} from 'react-native';
-import lodashGet from 'lodash/get';
-import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../../../../components/withLocalize';
-import PopoverWithMeasuredContent from '../../../../../components/PopoverWithMeasuredContent';
-import BaseReactionList from '../BaseReactionList';
-import compose from '../../../../../libs/compose';
-import withCurrentUserPersonalDetails from '../../../../../components/withCurrentUserPersonalDetails';
-import * as PersonalDetailsUtils from '../../../../../libs/PersonalDetailsUtils';
-import * as EmojiUtils from '../../../../../libs/EmojiUtils';
-import CONST from '../../../../../CONST';
-import ONYXKEYS from '../../../../../ONYXKEYS';
-import EmojiReactionsPropTypes from '../../../../../components/Reactions/EmojiReactionsPropTypes';
+import _ from 'underscore';
+import PopoverWithMeasuredContent from '@components/PopoverWithMeasuredContent';
+import EmojiReactionsPropTypes from '@components/Reactions/EmojiReactionsPropTypes';
+import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import BaseReactionList from '@pages/home/report/ReactionList/BaseReactionList';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
reportActionID: PropTypes.string,
diff --git a/src/pages/home/report/ReactionList/PopoverReactionList/index.js b/src/pages/home/report/ReactionList/PopoverReactionList/index.js
index 327885249843..9f1e7b3113fc 100644
--- a/src/pages/home/report/ReactionList/PopoverReactionList/index.js
+++ b/src/pages/home/report/ReactionList/PopoverReactionList/index.js
@@ -1,5 +1,5 @@
-import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react';
import PropTypes from 'prop-types';
+import React, {forwardRef, useImperativeHandle, useRef, useState} from 'react';
import BasePopoverReactionList from './BasePopoverReactionList';
const propTypes = {
diff --git a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js
index 36cd9428b738..b4845e943a74 100644
--- a/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js
+++ b/src/pages/home/report/ReportActionCompose/AttachmentPickerWithMenuItems.js
@@ -1,25 +1,25 @@
+import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import styles from '../../../../styles/styles';
-import Icon from '../../../../components/Icon';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import AttachmentPicker from '../../../../components/AttachmentPicker';
-import * as Report from '../../../../libs/actions/Report';
-import PopoverMenu from '../../../../components/PopoverMenu';
-import CONST from '../../../../CONST';
-import Tooltip from '../../../../components/Tooltip/PopoverAnchorTooltip';
-import * as Browser from '../../../../libs/Browser';
-import PressableWithFeedback from '../../../../components/Pressable/PressableWithFeedback';
-import useLocalize from '../../../../hooks/useLocalize';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
-import * as ReportUtils from '../../../../libs/ReportUtils';
-import * as IOU from '../../../../libs/actions/IOU';
-import * as Task from '../../../../libs/actions/Task';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import Permissions from '../../../../libs/Permissions';
+import AttachmentPicker from '@components/AttachmentPicker';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PopoverMenu from '@components/PopoverMenu';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Tooltip from '@components/Tooltip/PopoverAnchorTooltip';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import Permissions from '@libs/Permissions';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
+import * as IOU from '@userActions/IOU';
+import * as Report from '@userActions/Report';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Beta features list */
diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
index e194d0870885..b7013fe4ff2f 100644
--- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
+++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
@@ -1,41 +1,42 @@
-import React, {useEffect, useCallback, useState, useRef, useMemo, useImperativeHandle} from 'react';
-import {View, NativeModules, findNodeHandle} from 'react-native';
+import {useIsFocused, useNavigation} from '@react-navigation/native';
+import lodashGet from 'lodash/get';
+import React, {useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
+import {findNodeHandle, NativeModules, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import {useIsFocused, useNavigation} from '@react-navigation/native';
-import styles from '../../../../styles/styles';
-import themeColors from '../../../../styles/themes/default';
-import Composer from '../../../../components/Composer';
-import containerComposeStyles from '../../../../styles/containerComposeStyles';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
-import CONST from '../../../../CONST';
-import * as Browser from '../../../../libs/Browser';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import * as KeyDownListener from '../../../../libs/KeyboardShortcut/KeyDownPressListener';
-import * as EmojiPickerActions from '../../../../libs/actions/EmojiPickerAction';
-import willBlurTextInputOnTapOutsideFunc from '../../../../libs/willBlurTextInputOnTapOutside';
-import ReportActionComposeFocusManager from '../../../../libs/ReportActionComposeFocusManager';
-import * as ComposerUtils from '../../../../libs/ComposerUtils';
-import * as Report from '../../../../libs/actions/Report';
-import usePrevious from '../../../../hooks/usePrevious';
-import * as EmojiUtils from '../../../../libs/EmojiUtils';
-import * as User from '../../../../libs/actions/User';
-import * as ReportUtils from '../../../../libs/ReportUtils';
-import * as SuggestionUtils from '../../../../libs/SuggestionUtils';
-import * as ReportActionsUtils from '../../../../libs/ReportActionsUtils';
-import canFocusInputOnScreenFocus from '../../../../libs/canFocusInputOnScreenFocus';
+import Composer from '@components/Composer';
+import withKeyboardState from '@components/withKeyboardState';
+import useDebounce from '@hooks/useDebounce';
+import useLocalize from '@hooks/useLocalize';
+import usePrevious from '@hooks/usePrevious';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
+import compose from '@libs/compose';
+import * as ComposerUtils from '@libs/ComposerUtils';
+import getDraftComment from '@libs/ComposerUtils/getDraftComment';
+import convertToLTRForComposer from '@libs/convertToLTRForComposer';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import focusWithDelay from '@libs/focusWithDelay';
+import * as KeyDownListener from '@libs/KeyboardShortcut/KeyDownPressListener';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as SuggestionUtils from '@libs/SuggestionUtils';
+import updateMultilineInputRange from '@libs/UpdateMultilineInputRange';
+import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside';
+import containerComposeStyles from '@styles/containerComposeStyles';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as EmojiPickerActions from '@userActions/EmojiPickerAction';
+import * as InputFocus from '@userActions/InputFocus';
+import * as Report from '@userActions/Report';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import {defaultProps, propTypes} from './composerWithSuggestionsProps';
import SilentCommentUpdater from './SilentCommentUpdater';
import Suggestions from './Suggestions';
-import getDraftComment from '../../../../libs/ComposerUtils/getDraftComment';
-import useLocalize from '../../../../hooks/useLocalize';
-import compose from '../../../../libs/compose';
-import withKeyboardState from '../../../../components/withKeyboardState';
-import {propTypes, defaultProps} from './composerWithSuggestionsProps';
-import focusWithDelay from '../../../../libs/focusWithDelay';
-import useDebounce from '../../../../hooks/useDebounce';
-import updateMultilineInputRange from '../../../../libs/UpdateMultilineInputRange';
-import * as InputFocus from '../../../../libs/actions/InputFocus';
const {RNTextInputReset} = NativeModules;
@@ -121,7 +122,8 @@ function ComposerWithSuggestions({
const maxComposerLines = isSmallScreenWidth ? CONST.COMPOSER.MAX_LINES_SMALL_SCREEN : CONST.COMPOSER.MAX_LINES;
const isEmptyChat = useMemo(() => _.size(reportActions) === 1, [reportActions]);
- const shouldAutoFocus = !modal.isVisible && (shouldFocusInputOnScreenFocus || isEmptyChat) && shouldShowComposeInput;
+ const parentAction = ReportActionsUtils.getParentReportAction(report);
+ const shouldAutoFocus = !modal.isVisible && (shouldFocusInputOnScreenFocus || (isEmptyChat && !ReportActionsUtils.isTransactionThread(parentAction))) && shouldShowComposeInput;
const valueRef = useRef(value);
valueRef.current = value;
@@ -212,7 +214,6 @@ function ComposerWithSuggestions({
(commentValue, shouldDebounceSaveComment) => {
raiseIsScrollLikelyLayoutTriggered();
const {text: newComment, emojis} = EmojiUtils.replaceAndExtractEmojis(commentValue, preferredSkinTone, preferredLocale);
-
if (!_.isEmpty(emojis)) {
const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current);
if (!_.isEmpty(newEmojis)) {
@@ -224,9 +225,10 @@ function ComposerWithSuggestions({
debouncedUpdateFrequentlyUsedEmojis();
}
}
+ const newCommentConverted = convertToLTRForComposer(newComment);
emojisPresentBefore.current = emojis;
- setIsCommentEmpty(!!newComment.match(/^(\s)*$/));
- setValue(newComment);
+ setIsCommentEmpty(!!newCommentConverted.match(/^(\s)*$/));
+ setValue(newCommentConverted);
if (commentValue !== newComment) {
const remainder = ComposerUtils.getCommonSuffixLength(commentValue, newComment);
setSelection({
@@ -236,22 +238,22 @@ function ComposerWithSuggestions({
}
// Indicate that draft has been created.
- if (commentRef.current.length === 0 && newComment.length !== 0) {
+ if (commentRef.current.length === 0 && newCommentConverted.length !== 0) {
Report.setReportWithDraft(reportID, true);
}
// The draft has been deleted.
- if (newComment.length === 0) {
+ if (newCommentConverted.length === 0) {
Report.setReportWithDraft(reportID, false);
}
- commentRef.current = newComment;
+ commentRef.current = newCommentConverted;
if (shouldDebounceSaveComment) {
- debouncedSaveReportComment(reportID, newComment);
+ debouncedSaveReportComment(reportID, newCommentConverted);
} else {
- Report.saveReportComment(reportID, newComment || '');
+ Report.saveReportComment(reportID, newCommentConverted || '');
}
- if (newComment) {
+ if (newCommentConverted) {
debouncedBroadcastUserIsTyping(reportID);
}
},
@@ -457,19 +459,19 @@ function ComposerWithSuggestions({
}, []);
useEffect(() => {
- const unsubscribeNavigationBlur = navigation.addListener('blur', () => KeyDownListener.removeKeyDownPressListner(focusComposerOnKeyPress));
+ const unsubscribeNavigationBlur = navigation.addListener('blur', () => KeyDownListener.removeKeyDownPressListener(focusComposerOnKeyPress));
const unsubscribeNavigationFocus = navigation.addListener('focus', () => {
- KeyDownListener.addKeyDownPressListner(focusComposerOnKeyPress);
+ KeyDownListener.addKeyDownPressListener(focusComposerOnKeyPress);
setUpComposeFocusManager();
});
- KeyDownListener.addKeyDownPressListner(focusComposerOnKeyPress);
+ KeyDownListener.addKeyDownPressListener(focusComposerOnKeyPress);
setUpComposeFocusManager();
return () => {
ReportActionComposeFocusManager.clear(true);
- KeyDownListener.removeKeyDownPressListner(focusComposerOnKeyPress);
+ KeyDownListener.removeKeyDownPressListener(focusComposerOnKeyPress);
unsubscribeNavigationBlur();
unsubscribeNavigationFocus();
};
@@ -594,6 +596,16 @@ ComposerWithSuggestions.propTypes = propTypes;
ComposerWithSuggestions.defaultProps = defaultProps;
ComposerWithSuggestions.displayName = 'ComposerWithSuggestions';
+const ComposerWithSuggestionsWithRef = React.forwardRef((props, ref) => (
+
+));
+
+ComposerWithSuggestionsWithRef.displayName = 'ComposerWithSuggestionsWithRef';
+
export default compose(
withKeyboardState,
withOnyx({
@@ -619,12 +631,4 @@ export default compose(
initWithStoredValues: false,
},
}),
-)(
- React.forwardRef((props, ref) => (
-
- )),
-);
+)(ComposerWithSuggestionsWithRef);
diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js
index dd4d51653546..f090a942e097 100644
--- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js
+++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js
@@ -1,43 +1,43 @@
-import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {PortalHost} from '@gorhom/portal';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
import {runOnJS, useAnimatedRef} from 'react-native-reanimated';
-import {PortalHost} from '@gorhom/portal';
-import styles from '../../../../styles/styles';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import * as Report from '../../../../libs/actions/Report';
-import ReportTypingIndicator from '../ReportTypingIndicator';
-import AttachmentModal from '../../../../components/AttachmentModal';
-import compose from '../../../../libs/compose';
-import willBlurTextInputOnTapOutsideFunc from '../../../../libs/willBlurTextInputOnTapOutside';
-import canFocusInputOnScreenFocus from '../../../../libs/canFocusInputOnScreenFocus';
-import CONST from '../../../../CONST';
-import * as ReportUtils from '../../../../libs/ReportUtils';
-import participantPropTypes from '../../../../components/participantPropTypes';
-import ParticipantLocalTime from '../ParticipantLocalTime';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../../components/withCurrentUserPersonalDetails';
-import {withNetwork} from '../../../../components/OnyxProvider';
-import * as User from '../../../../libs/actions/User';
-import EmojiPickerButton from '../../../../components/EmojiPicker/EmojiPickerButton';
-import * as DeviceCapabilities from '../../../../libs/DeviceCapabilities';
-import OfflineIndicator from '../../../../components/OfflineIndicator';
-import ExceededCommentLength from '../../../../components/ExceededCommentLength';
-import ReportDropUI from '../ReportDropUI';
-import reportPropTypes from '../../../reportPropTypes';
-import OfflineWithFeedback from '../../../../components/OfflineWithFeedback';
-import SendButton from './SendButton';
+import _ from 'underscore';
+import AttachmentModal from '@components/AttachmentModal';
+import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton';
+import ExceededCommentLength from '@components/ExceededCommentLength';
+import OfflineIndicator from '@components/OfflineIndicator';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {withNetwork} from '@components/OnyxProvider';
+import participantPropTypes from '@components/participantPropTypes';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
+import compose from '@libs/compose';
+import getDraftComment from '@libs/ComposerUtils/getDraftComment';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import getModalState from '@libs/getModalState';
+import * as ReportUtils from '@libs/ReportUtils';
+import updatePropsPaperWorklet from '@libs/updatePropsPaperWorklet';
+import willBlurTextInputOnTapOutsideFunc from '@libs/willBlurTextInputOnTapOutside';
+import ParticipantLocalTime from '@pages/home/report/ParticipantLocalTime';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import ReportDropUI from '@pages/home/report/ReportDropUI';
+import ReportTypingIndicator from '@pages/home/report/ReportTypingIndicator';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as EmojiPickerActions from '@userActions/EmojiPickerAction';
+import * as Report from '@userActions/Report';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import AttachmentPickerWithMenuItems from './AttachmentPickerWithMenuItems';
import ComposerWithSuggestions from './ComposerWithSuggestions';
-import reportActionPropTypes from '../reportActionPropTypes';
-import useLocalize from '../../../../hooks/useLocalize';
-import getModalState from '../../../../libs/getModalState';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
-import * as EmojiPickerActions from '../../../../libs/actions/EmojiPickerAction';
-import getDraftComment from '../../../../libs/ComposerUtils/getDraftComment';
-import updatePropsPaperWorklet from '../../../../libs/updatePropsPaperWorklet';
+import SendButton from './SendButton';
const propTypes = {
/** A method to call when the form is submitted */
@@ -342,120 +342,122 @@ function ReportActionCompose({
}, [isSendDisabled, resetFullComposerSize, submitForm, animatedRef, isReportReadyForDisplay]);
return (
-
-
-
+
+
{shouldShowReportRecipientLocalTime && hasReportRecipient && }
-
+
+
+
- setIsAttachmentPreviewActive(true)}
- onModalHide={onAttachmentPreviewClose}
+
- {({displayFileInModal}) => (
- <>
-
-
- {
- if (isAttachmentPreviewActive) {
- return;
- }
- const data = lodashGet(e, ['dataTransfer', 'items', 0]);
- displayFileInModal(data);
- }}
- />
- >
+ setIsAttachmentPreviewActive(true)}
+ onModalHide={onAttachmentPreviewClose}
+ >
+ {({displayFileInModal}) => (
+ <>
+
+
+ {
+ if (isAttachmentPreviewActive) {
+ return;
+ }
+ const data = lodashGet(e, ['dataTransfer', 'items', 0]);
+ displayFileInModal(data);
+ }}
+ />
+ >
+ )}
+
+ {DeviceCapabilities.canUseTouchScreen() && isMediumScreenWidth ? null : (
+ composerRef.current.replaceSelectionWithText(...args)}
+ emojiPickerID={report.reportID}
+ />
)}
-
- {DeviceCapabilities.canUseTouchScreen() && isMediumScreenWidth ? null : (
- composerRef.current.replaceSelectionWithText(...args)}
- emojiPickerID={report.reportID}
+
- )}
-
-
-
- {!isSmallScreenWidth && }
-
-
-
-
+
+
+ {!isSmallScreenWidth && }
+
+
+
+
+
);
}
diff --git a/src/pages/home/report/ReportActionCompose/SendButton.js b/src/pages/home/report/ReportActionCompose/SendButton.js
index a97dd420e181..061251d13c01 100644
--- a/src/pages/home/report/ReportActionCompose/SendButton.js
+++ b/src/pages/home/report/ReportActionCompose/SendButton.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
-import PropTypes from 'prop-types';
-import styles from '../../../../styles/styles';
-import themeColors from '../../../../styles/themes/default';
-import Icon from '../../../../components/Icon';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import CONST from '../../../../CONST';
-import Tooltip from '../../../../components/Tooltip';
-import PressableWithFeedback from '../../../../components/Pressable/PressableWithFeedback';
-import useLocalize from '../../../../hooks/useLocalize';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Tooltip from '@components/Tooltip';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
const propTypes = {
/** Whether the button is disabled */
diff --git a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js
index 09f9d368bdcc..9aa997a892f4 100644
--- a/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js
+++ b/src/pages/home/report/ReportActionCompose/SilentCommentUpdater.js
@@ -1,9 +1,9 @@
+import PropTypes from 'prop-types';
import {useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import usePrevious from '../../../../hooks/usePrevious';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import useLocalize from '../../../../hooks/useLocalize';
+import useLocalize from '@hooks/useLocalize';
+import usePrevious from '@hooks/usePrevious';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The comment of the report */
@@ -44,6 +44,11 @@ function SilentCommentUpdater({comment, commentRef, report, value, updateComment
const {preferredLocale} = useLocalize();
const prevPreferredLocale = usePrevious(preferredLocale);
+ useEffect(() => {
+ updateComment(comment);
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- We need to run this on mount
+ }, []);
+
useEffect(() => {
// Value state does not have the same value as comment props when the comment gets changed from another tab.
// In this case, we should synchronize the value between tabs.
diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js
index 857b7d5e52c2..dc84f77b6311 100644
--- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js
+++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js
@@ -1,14 +1,14 @@
-import React, {useState, useCallback, useRef, useImperativeHandle} from 'react';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React, {useCallback, useImperativeHandle, useRef, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../../../../CONST';
-import useArrowKeyFocusManager from '../../../../hooks/useArrowKeyFocusManager';
-import * as SuggestionsUtils from '../../../../libs/SuggestionUtils';
-import * as EmojiUtils from '../../../../libs/EmojiUtils';
-import EmojiSuggestions from '../../../../components/EmojiSuggestions';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import useLocalize from '../../../../hooks/useLocalize';
+import _ from 'underscore';
+import EmojiSuggestions from '@components/EmojiSuggestions';
+import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager';
+import useLocalize from '@hooks/useLocalize';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import * as SuggestionsUtils from '@libs/SuggestionUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as SuggestionProps from './suggestionProps';
/**
@@ -248,6 +248,8 @@ const SuggestionEmojiWithRef = React.forwardRef((props, ref) => (
/>
));
+SuggestionEmojiWithRef.displayName = 'SuggestionEmojiWithRef';
+
export default withOnyx({
preferredSkinTone: {
key: ONYXKEYS.PREFERRED_EMOJI_SKIN_TONE,
diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.js b/src/pages/home/report/ReportActionCompose/SuggestionMention.js
index 59221f57fd4b..baf93da6ccc4 100644
--- a/src/pages/home/report/ReportActionCompose/SuggestionMention.js
+++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.js
@@ -1,17 +1,17 @@
-import React, {useState, useCallback, useRef, useImperativeHandle, useEffect} from 'react';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../../../../CONST';
-import useArrowKeyFocusManager from '../../../../hooks/useArrowKeyFocusManager';
-import MentionSuggestions from '../../../../components/MentionSuggestions';
-import * as UserUtils from '../../../../libs/UserUtils';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import * as SuggestionsUtils from '../../../../libs/SuggestionUtils';
-import useLocalize from '../../../../hooks/useLocalize';
-import usePrevious from '../../../../hooks/usePrevious';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import personalDetailsPropType from '../../../personalDetailsPropType';
+import _ from 'underscore';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MentionSuggestions from '@components/MentionSuggestions';
+import useArrowKeyFocusManager from '@hooks/useArrowKeyFocusManager';
+import useLocalize from '@hooks/useLocalize';
+import usePrevious from '@hooks/usePrevious';
+import * as SuggestionsUtils from '@libs/SuggestionUtils';
+import * as UserUtils from '@libs/UserUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as SuggestionProps from './suggestionProps';
/**
@@ -306,16 +306,18 @@ SuggestionMention.propTypes = propTypes;
SuggestionMention.defaultProps = defaultProps;
SuggestionMention.displayName = 'SuggestionMention';
+const SuggestionMentionWithRef = React.forwardRef((props, ref) => (
+
+));
+
+SuggestionMentionWithRef.displayName = 'SuggestionMentionWithRef';
+
export default withOnyx({
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
-})(
- React.forwardRef((props, ref) => (
-
- )),
-);
+})(SuggestionMentionWithRef);
diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.js b/src/pages/home/report/ReportActionCompose/Suggestions.js
index 74e9e79471e7..f39a70a960cf 100644
--- a/src/pages/home/report/ReportActionCompose/Suggestions.js
+++ b/src/pages/home/report/ReportActionCompose/Suggestions.js
@@ -1,7 +1,7 @@
-import React, {useRef, useCallback, useImperativeHandle} from 'react';
import PropTypes from 'prop-types';
-import SuggestionMention from './SuggestionMention';
+import React, {useCallback, useImperativeHandle, useRef} from 'react';
import SuggestionEmoji from './SuggestionEmoji';
+import SuggestionMention from './SuggestionMention';
import * as SuggestionProps from './suggestionProps';
const propTypes = {
@@ -128,10 +128,14 @@ Suggestions.propTypes = propTypes;
Suggestions.defaultProps = defaultProps;
Suggestions.displayName = 'Suggestions';
-export default React.forwardRef((props, ref) => (
+const SuggestionsWithRef = React.forwardRef((props, ref) => (
));
+
+SuggestionsWithRef.displayName = 'SuggestionsWithRef';
+
+export default SuggestionsWithRef;
diff --git a/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js b/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js
index 017b5aecb4ae..46d34d407b1c 100644
--- a/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js
+++ b/src/pages/home/report/ReportActionCompose/composerWithSuggestionsProps.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import reportActionPropTypes from '../reportActionPropTypes';
-import CONST from '../../../../CONST';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import CONST from '@src/CONST';
const propTypes = {
/** Details about any modals being used */
diff --git a/src/pages/home/report/ReportActionItem.js b/src/pages/home/report/ReportActionItem.js
index 2ae8c5c4ccdc..a7a3bc0739f3 100644
--- a/src/pages/home/report/ReportActionItem.js
+++ b/src/pages/home/report/ReportActionItem.js
@@ -1,78 +1,78 @@
-import _ from 'underscore';
import lodashGet from 'lodash/get';
-import React, {useState, useRef, useEffect, memo, useCallback, useContext, useMemo} from 'react';
-import {InteractionManager, View} from 'react-native';
import PropTypes from 'prop-types';
+import React, {memo, useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
+import {InteractionManager, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import CONST from '../../../CONST';
-import ONYXKEYS from '../../../ONYXKEYS';
-import reportActionPropTypes from './reportActionPropTypes';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import PressableWithSecondaryInteraction from '../../../components/PressableWithSecondaryInteraction';
-import Hoverable from '../../../components/Hoverable';
-import Button from '../../../components/Button';
-import ReportActionItemSingle from './ReportActionItemSingle';
-import ReportActionItemGrouped from './ReportActionItemGrouped';
-import MoneyRequestAction from '../../../components/ReportActionItem/MoneyRequestAction';
-import ReportActionItemMessage from './ReportActionItemMessage';
-import UnreadActionIndicator from '../../../components/UnreadActionIndicator';
-import ReportActionItemMessageEdit from './ReportActionItemMessageEdit';
-import ReportActionItemCreated from './ReportActionItemCreated';
-import ReportActionItemThread from './ReportActionItemThread';
-import LinkPreviewer from './LinkPreviewer';
-import compose from '../../../libs/compose';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import ControlSelection from '../../../libs/ControlSelection';
-import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
+import _ from 'underscore';
+import Button from '@components/Button';
+import DisplayNames from '@components/DisplayNames';
+import Hoverable from '@components/Hoverable';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import InlineSystemMessage from '@components/InlineSystemMessage';
+import KYCWall from '@components/KYCWall';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {usePersonalDetails, withBlockedFromConcierge, withNetwork, withReportActionsDrafts} from '@components/OnyxProvider';
+import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import EmojiReactionsPropTypes from '@components/Reactions/EmojiReactionsPropTypes';
+import ReportActionItemEmojiReactions from '@components/Reactions/ReportActionItemEmojiReactions';
+import RenderHTML from '@components/RenderHTML';
+import ChronosOOOListActions from '@components/ReportActionItem/ChronosOOOListActions';
+import MoneyReportView from '@components/ReportActionItem/MoneyReportView';
+import MoneyRequestAction from '@components/ReportActionItem/MoneyRequestAction';
+import MoneyRequestView from '@components/ReportActionItem/MoneyRequestView';
+import RenameAction from '@components/ReportActionItem/RenameAction';
+import ReportPreview from '@components/ReportActionItem/ReportPreview';
+import TaskAction from '@components/ReportActionItem/TaskAction';
+import TaskPreview from '@components/ReportActionItem/TaskPreview';
+import TaskView from '@components/ReportActionItem/TaskView';
+import {ShowContextMenuContext} from '@components/ShowContextMenuContext';
+import Text from '@components/Text';
+import UnreadActionIndicator from '@components/UnreadActionIndicator';
+import withLocalize from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import usePrevious from '@hooks/usePrevious';
+import compose from '@libs/compose';
+import ControlSelection from '@libs/ControlSelection';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import focusTextInputAfterAnimation from '@libs/focusTextInputAfterAnimation';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import SelectionScraper from '@libs/SelectionScraper';
+import userWalletPropTypes from '@pages/EnablePayments/userWalletPropTypes';
+import {ReactionListContext} from '@pages/home/ReportScreenContext';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
+import * as store from '@userActions/ReimbursementAccount/store';
+import * as Report from '@userActions/Report';
+import * as ReportActions from '@userActions/ReportActions';
+import * as Session from '@userActions/Session';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import * as ContextMenuActions from './ContextMenu/ContextMenuActions';
import MiniReportActionContextMenu from './ContextMenu/MiniReportActionContextMenu';
import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu';
-import * as ContextMenuActions from './ContextMenu/ContextMenuActions';
-import * as EmojiPickerAction from '../../../libs/actions/EmojiPickerAction';
-import {usePersonalDetails, withBlockedFromConcierge, withNetwork, withReportActionsDrafts} from '../../../components/OnyxProvider';
-import RenameAction from '../../../components/ReportActionItem/RenameAction';
-import InlineSystemMessage from '../../../components/InlineSystemMessage';
-import styles from '../../../styles/styles';
-import SelectionScraper from '../../../libs/SelectionScraper';
-import focusTextInputAfterAnimation from '../../../libs/focusTextInputAfterAnimation';
-import * as User from '../../../libs/actions/User';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import * as ReportActions from '../../../libs/actions/ReportActions';
-import reportPropTypes from '../../reportPropTypes';
-import {ShowContextMenuContext} from '../../../components/ShowContextMenuContext';
-import ChronosOOOListActions from '../../../components/ReportActionItem/ChronosOOOListActions';
-import ReportActionItemEmojiReactions from '../../../components/Reactions/ReportActionItemEmojiReactions';
-import * as Report from '../../../libs/actions/Report';
-import withLocalize from '../../../components/withLocalize';
-import Icon from '../../../components/Icon';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import Text from '../../../components/Text';
-import DisplayNames from '../../../components/DisplayNames';
-import ReportPreview from '../../../components/ReportActionItem/ReportPreview';
-import ReportActionItemDraft from './ReportActionItemDraft';
-import TaskPreview from '../../../components/ReportActionItem/TaskPreview';
-import TaskAction from '../../../components/ReportActionItem/TaskAction';
-import EmojiReactionsPropTypes from '../../../components/Reactions/EmojiReactionsPropTypes';
-import TaskView from '../../../components/ReportActionItem/TaskView';
-import MoneyReportView from '../../../components/ReportActionItem/MoneyReportView';
-import * as Session from '../../../libs/actions/Session';
-import MoneyRequestView from '../../../components/ReportActionItem/MoneyRequestView';
import {hideContextMenu} from './ContextMenu/ReportActionContextMenu';
-import * as PersonalDetailsUtils from '../../../libs/PersonalDetailsUtils';
-import * as store from '../../../libs/actions/ReimbursementAccount/store';
-import * as BankAccounts from '../../../libs/actions/BankAccounts';
-import {ReactionListContext} from '../ReportScreenContext';
-import usePrevious from '../../../hooks/usePrevious';
-import Permissions from '../../../libs/Permissions';
-import themeColors from '../../../styles/themes/default';
+import LinkPreviewer from './LinkPreviewer';
import ReportActionItemBasicMessage from './ReportActionItemBasicMessage';
-import RenderHTML from '../../../components/RenderHTML';
+import ReportActionItemCreated from './ReportActionItemCreated';
+import ReportActionItemDraft from './ReportActionItemDraft';
+import ReportActionItemGrouped from './ReportActionItemGrouped';
+import ReportActionItemMessage from './ReportActionItemMessage';
+import ReportActionItemMessageEdit from './ReportActionItemMessageEdit';
+import ReportActionItemSingle from './ReportActionItemSingle';
+import ReportActionItemThread from './ReportActionItemThread';
+import reportActionPropTypes from './reportActionPropTypes';
import ReportAttachmentsContext from './ReportAttachmentsContext';
-import ROUTES from '../../../ROUTES';
-import Navigation from '../../../libs/Navigation/Navigation';
-import KYCWall from '../../../components/KYCWall';
-import userWalletPropTypes from '../../EnablePayments/userWalletPropTypes';
const propTypes = {
...windowDimensionsPropTypes,
@@ -134,7 +134,7 @@ const defaultProps = {
function ReportActionItem(props) {
const personalDetails = usePersonalDetails() || CONST.EMPTY_OBJECT;
- const [isContextMenuActive, setIsContextMenuActive] = useState(ReportActionContextMenu.isActiveReportAction(props.action.reportActionID));
+ const [isContextMenuActive, setIsContextMenuActive] = useState(() => ReportActionContextMenu.isActiveReportAction(props.action.reportActionID));
const [isHidden, setIsHidden] = useState(false);
const [moderationDecision, setModerationDecision] = useState(CONST.MODERATION.MODERATOR_DECISION_APPROVED);
const reactionListRef = useContext(ReactionListContext);
@@ -725,8 +725,8 @@ export default compose(
propName: 'draftMessage',
transformValue: (drafts, props) => {
const originalReportID = ReportUtils.getOriginalReportID(props.report.reportID, props.action);
- const draftKey = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${originalReportID}_${props.action.reportActionID}`;
- return lodashGet(drafts, draftKey, '');
+ const draftKey = `${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}${originalReportID}`;
+ return lodashGet(drafts, [draftKey, props.action.reportActionID], '');
},
}),
withOnyx({
diff --git a/src/pages/home/report/ReportActionItemBasicMessage.js b/src/pages/home/report/ReportActionItemBasicMessage.js
index fa33826d39a4..87997b29b833 100644
--- a/src/pages/home/report/ReportActionItemBasicMessage.js
+++ b/src/pages/home/report/ReportActionItemBasicMessage.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
+import Text from '@components/Text';
+import styles from '@styles/styles';
const propTypes = {
message: PropTypes.string.isRequired,
diff --git a/src/pages/home/report/ReportActionItemCreated.js b/src/pages/home/report/ReportActionItemCreated.js
index 50b4a3eb6148..10ebb13302b2 100644
--- a/src/pages/home/report/ReportActionItemCreated.js
+++ b/src/pages/home/report/ReportActionItemCreated.js
@@ -1,25 +1,25 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {memo} from 'react';
import {View} from 'react-native';
-import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import ONYXKEYS from '../../../ONYXKEYS';
-import ReportWelcomeText from '../../../components/ReportWelcomeText';
-import participantPropTypes from '../../../components/participantPropTypes';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import styles from '../../../styles/styles';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import * as Report from '../../../libs/actions/Report';
-import reportPropTypes from '../../reportPropTypes';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import compose from '../../../libs/compose';
-import withLocalize from '../../../components/withLocalize';
-import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback';
-import MultipleAvatars from '../../../components/MultipleAvatars';
-import CONST from '../../../CONST';
+import MultipleAvatars from '@components/MultipleAvatars';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import participantPropTypes from '@components/participantPropTypes';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import ReportWelcomeText from '@components/ReportWelcomeText';
+import withLocalize from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import reportWithoutHasDraftSelector from '@libs/OnyxSelectors/reportWithoutHasDraftSelector';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground';
-import reportWithoutHasDraftSelector from '../../../libs/OnyxSelectors/reportWithoutHasDraftSelector';
const propTypes = {
/** The id of the report */
diff --git a/src/pages/home/report/ReportActionItemDate.js b/src/pages/home/report/ReportActionItemDate.js
index 0e6af2e95636..346a1c2683f0 100644
--- a/src/pages/home/report/ReportActionItemDate.js
+++ b/src/pages/home/report/ReportActionItemDate.js
@@ -1,10 +1,10 @@
-import React, {memo} from 'react';
import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import compose from '../../../libs/compose';
-import Text from '../../../components/Text';
-import {withCurrentDate} from '../../../components/OnyxProvider';
+import React, {memo} from 'react';
+import {withCurrentDate} from '@components/OnyxProvider';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
const propTypes = {
/** UTC timestamp for when the action was created */
diff --git a/src/pages/home/report/ReportActionItemDraft.js b/src/pages/home/report/ReportActionItemDraft.js
index b3b66994fb9c..500c4146e608 100644
--- a/src/pages/home/report/ReportActionItemDraft.js
+++ b/src/pages/home/report/ReportActionItemDraft.js
@@ -1,7 +1,7 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
+import styles from '@styles/styles';
const propTypes = {
/** Children view component for this action item */
diff --git a/src/pages/home/report/ReportActionItemFragment.js b/src/pages/home/report/ReportActionItemFragment.js
index 57b51ef50519..24e1c6bc1ef6 100644
--- a/src/pages/home/report/ReportActionItemFragment.js
+++ b/src/pages/home/report/ReportActionItemFragment.js
@@ -1,24 +1,24 @@
-import React, {memo} from 'react';
-import PropTypes from 'prop-types';
import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
+import React, {memo} from 'react';
+import avatarPropTypes from '@components/avatarPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import RenderHTML from '@components/RenderHTML';
+import Text from '@components/Text';
+import UserDetailsTooltip from '@components/UserDetailsTooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import ZeroWidthView from '@components/ZeroWidthView';
+import compose from '@libs/compose';
+import convertToLTR from '@libs/convertToLTR';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import editedLabelStyles from '@styles/editedLabelStyles';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
import reportActionFragmentPropTypes from './reportActionFragmentPropTypes';
-import styles from '../../../styles/styles';
-import variables from '../../../styles/variables';
-import themeColors from '../../../styles/themes/default';
-import RenderHTML from '../../../components/RenderHTML';
-import Text from '../../../components/Text';
-import * as EmojiUtils from '../../../libs/EmojiUtils';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
-import compose from '../../../libs/compose';
-import convertToLTR from '../../../libs/convertToLTR';
-import {withNetwork} from '../../../components/OnyxProvider';
-import CONST from '../../../CONST';
-import editedLabelStyles from '../../../styles/editedLabelStyles';
-import UserDetailsTooltip from '../../../components/UserDetailsTooltip';
-import avatarPropTypes from '../../../components/avatarPropTypes';
-import ZeroWidthView from '../../../components/ZeroWidthView';
const propTypes = {
/** Users accountID */
diff --git a/src/pages/home/report/ReportActionItemGrouped.js b/src/pages/home/report/ReportActionItemGrouped.js
index e60bf01835f8..2d55ecbbe037 100644
--- a/src/pages/home/report/ReportActionItemGrouped.js
+++ b/src/pages/home/report/ReportActionItemGrouped.js
@@ -1,7 +1,7 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
+import styles from '@styles/styles';
const propTypes = {
/** Children view component for this action item */
diff --git a/src/pages/home/report/ReportActionItemMessage.js b/src/pages/home/report/ReportActionItemMessage.js
index 88223e6480ff..37aaa5adf287 100644
--- a/src/pages/home/report/ReportActionItemMessage.js
+++ b/src/pages/home/report/ReportActionItemMessage.js
@@ -1,14 +1,14 @@
-import React from 'react';
-import {View, Text} from 'react-native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React from 'react';
+import {Text, View} from 'react-native';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import styles from '../../../styles/styles';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import styles from '@styles/styles';
import ReportActionItemFragment from './ReportActionItemFragment';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
import reportActionPropTypes from './reportActionPropTypes';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
const propTypes = {
/** The report action */
diff --git a/src/pages/home/report/ReportActionItemMessageEdit.js b/src/pages/home/report/ReportActionItemMessageEdit.js
index 1d0f918de4f7..589b4c367c25 100644
--- a/src/pages/home/report/ReportActionItemMessageEdit.js
+++ b/src/pages/home/report/ReportActionItemMessageEdit.js
@@ -1,43 +1,43 @@
+import ExpensiMark from 'expensify-common/lib/ExpensiMark';
+import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
-import React, {useState, useRef, useMemo, useEffect, useCallback} from 'react';
-import {InteractionManager, Keyboard, View} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {InteractionManager, Keyboard, View} from 'react-native';
import _ from 'underscore';
-import ExpensiMark from 'expensify-common/lib/ExpensiMark';
-import Str from 'expensify-common/lib/str';
-import reportActionPropTypes from './reportActionPropTypes';
-import styles from '../../../styles/styles';
-import themeColors from '../../../styles/themes/default';
-import containerComposeStyles from '../../../styles/containerComposeStyles';
-import Composer from '../../../components/Composer';
-import * as Report from '../../../libs/actions/Report';
-import setShouldShowComposeInputKeyboardAware from '../../../libs/setShouldShowComposeInputKeyboardAware';
-import ReportActionComposeFocusManager from '../../../libs/ReportActionComposeFocusManager';
-import EmojiPickerButton from '../../../components/EmojiPicker/EmojiPickerButton';
-import Icon from '../../../components/Icon';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import Tooltip from '../../../components/Tooltip';
+import Composer from '@components/Composer';
+import EmojiPickerButton from '@components/EmojiPicker/EmojiPickerButton';
+import ExceededCommentLength from '@components/ExceededCommentLength';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import refPropTypes from '@components/refPropTypes';
+import Tooltip from '@components/Tooltip';
+import useKeyboardState from '@hooks/useKeyboardState';
+import useLocalize from '@hooks/useLocalize';
+import useReportScrollManager from '@hooks/useReportScrollManager';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import * as ComposerUtils from '@libs/ComposerUtils';
+import * as EmojiUtils from '@libs/EmojiUtils';
+import focusWithDelay from '@libs/focusWithDelay';
+import onyxSubscribe from '@libs/onyxSubscribe';
+import ReportActionComposeFocusManager from '@libs/ReportActionComposeFocusManager';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import setShouldShowComposeInputKeyboardAware from '@libs/setShouldShowComposeInputKeyboardAware';
+import reportPropTypes from '@pages/reportPropTypes';
+import containerComposeStyles from '@styles/containerComposeStyles';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as EmojiPickerAction from '@userActions/EmojiPickerAction';
+import * as InputFocus from '@userActions/InputFocus';
+import * as Report from '@userActions/Report';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as ReportActionContextMenu from './ContextMenu/ReportActionContextMenu';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
-import * as EmojiUtils from '../../../libs/EmojiUtils';
-import reportPropTypes from '../../reportPropTypes';
-import ExceededCommentLength from '../../../components/ExceededCommentLength';
-import CONST from '../../../CONST';
-import refPropTypes from '../../../components/refPropTypes';
-import * as ComposerUtils from '../../../libs/ComposerUtils';
-import * as User from '../../../libs/actions/User';
-import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback';
-import useLocalize from '../../../hooks/useLocalize';
-import useKeyboardState from '../../../hooks/useKeyboardState';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
-import useReportScrollManager from '../../../hooks/useReportScrollManager';
-import * as EmojiPickerAction from '../../../libs/actions/EmojiPickerAction';
-import focusWithDelay from '../../../libs/focusWithDelay';
-import * as Browser from '../../../libs/Browser';
-import * as InputFocus from '../../../libs/actions/InputFocus';
-import onyxSubscribe from '../../../libs/onyxSubscribe';
-import ONYXKEYS from '../../../ONYXKEYS';
+import reportActionPropTypes from './reportActionPropTypes';
const propTypes = {
/** All the data of the action */
@@ -111,7 +111,7 @@ function ReportActionItemMessageEdit(props) {
}
return initialDraft;
});
- const [selection, setSelection] = useState(getInitialSelection());
+ const [selection, setSelection] = useState(getInitialSelection);
const [isFocused, setIsFocused] = useState(false);
const [hasExceededMaxCommentLength, setHasExceededMaxCommentLength] = useState(false);
const [modal, setModal] = useState(false);
@@ -269,6 +269,11 @@ function ReportActionItemMessageEdit(props) {
[props.action.message, debouncedSaveDraft, debouncedUpdateFrequentlyUsedEmojis, props.preferredSkinTone, preferredLocale],
);
+ useEffect(() => {
+ updateDraft(draft);
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- run this only when language is changed
+ }, [props.action.reportActionID, preferredLocale]);
+
/**
* Delete the draft of the comment being edited. This will take the comment out of "edit mode" with the old content.
*/
@@ -286,7 +291,7 @@ function ReportActionItemMessageEdit(props) {
// Scroll to the last comment after editing to make sure the whole comment is clearly visible in the report.
if (props.index === 0) {
const keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', () => {
- reportScrollManager.scrollToIndex({animated: true, index: props.index}, false);
+ reportScrollManager.scrollToIndex(props.index, false);
keyboardDidHideListener.remove();
});
}
@@ -401,7 +406,7 @@ function ReportActionItemMessageEdit(props) {
style={[styles.textInputCompose, styles.flex1, styles.bgTransparent]}
onFocus={() => {
setIsFocused(true);
- reportScrollManager.scrollToIndex({animated: true, index: props.index}, true);
+ reportScrollManager.scrollToIndex(props.index, true);
setShouldShowComposeInputKeyboardAware(false);
// Clear active report action when another action gets focused
@@ -472,10 +477,14 @@ ReportActionItemMessageEdit.propTypes = propTypes;
ReportActionItemMessageEdit.defaultProps = defaultProps;
ReportActionItemMessageEdit.displayName = 'ReportActionItemMessageEdit';
-export default React.forwardRef((props, ref) => (
+const ReportActionItemMessageEditWithRef = React.forwardRef((props, ref) => (
));
+
+ReportActionItemMessageEditWithRef.displayName = 'ReportActionItemMessageEditWithRef';
+
+export default ReportActionItemMessageEditWithRef;
diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js
index b67707031372..e2274ce41ae0 100644
--- a/src/pages/home/report/ReportActionItemParentAction.js
+++ b/src/pages/home/report/ReportActionItemParentAction.js
@@ -1,21 +1,21 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import ONYXKEYS from '../../../ONYXKEYS';
-import styles from '../../../styles/styles';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import * as Report from '../../../libs/actions/Report';
-import reportPropTypes from '../../reportPropTypes';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import compose from '../../../libs/compose';
-import withLocalize from '../../../components/withLocalize';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import withLocalize from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as Report from '@userActions/Report';
+import ONYXKEYS from '@src/ONYXKEYS';
+import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground';
import ReportActionItem from './ReportActionItem';
import reportActionPropTypes from './reportActionPropTypes';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
-import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground';
const propTypes = {
/** Flag to show, hide the thread divider line */
diff --git a/src/pages/home/report/ReportActionItemSingle.js b/src/pages/home/report/ReportActionItemSingle.js
index fc189a3aef36..329952769a4f 100644
--- a/src/pages/home/report/ReportActionItemSingle.js
+++ b/src/pages/home/report/ReportActionItemSingle.js
@@ -1,36 +1,36 @@
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback, useMemo} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
-import reportActionPropTypes from './reportActionPropTypes';
-import ReportActionItemFragment from './ReportActionItemFragment';
-import styles from '../../../styles/styles';
+import _ from 'underscore';
+import Avatar from '@components/Avatar';
+import MultipleAvatars from '@components/MultipleAvatars';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {usePersonalDetails} from '@components/OnyxProvider';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import SubscriptAvatar from '@components/SubscriptAvatar';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import UserDetailsTooltip from '@components/UserDetailsTooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import ControlSelection from '@libs/ControlSelection';
+import DateUtils from '@libs/DateUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import ReportActionItemDate from './ReportActionItemDate';
-import Avatar from '../../../components/Avatar';
-import compose from '../../../libs/compose';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import {usePersonalDetails} from '../../../components/OnyxProvider';
-import ControlSelection from '../../../libs/ControlSelection';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import CONST from '../../../CONST';
-import SubscriptAvatar from '../../../components/SubscriptAvatar';
-import reportPropTypes from '../../reportPropTypes';
-import * as UserUtils from '../../../libs/UserUtils';
-import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback';
-import UserDetailsTooltip from '../../../components/UserDetailsTooltip';
-import MultipleAvatars from '../../../components/MultipleAvatars';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import themeColors from '../../../styles/themes/default';
-import Permissions from '../../../libs/Permissions';
-import ONYXKEYS from '../../../ONYXKEYS';
-import Text from '../../../components/Text';
-import Tooltip from '../../../components/Tooltip';
-import DateUtils from '../../../libs/DateUtils';
+import ReportActionItemFragment from './ReportActionItemFragment';
+import reportActionPropTypes from './reportActionPropTypes';
const propTypes = {
/** All the data of the action */
@@ -122,7 +122,10 @@ function ReportActionItemSingle(props) {
id: secondaryAccountId,
};
} else if (!isWorkspaceActor) {
- secondaryAvatar = ReportUtils.getIcons(props.report, {})[props.report.isOwnPolicyExpenseChat ? 0 : 1];
+ const avatarIconIndex = props.report.isOwnPolicyExpenseChat || ReportUtils.isPolicyExpenseChat(props.report) ? 0 : 1;
+ const reportIcons = ReportUtils.getIcons(props.report, {});
+
+ secondaryAvatar = reportIcons[avatarIconIndex];
}
const icon = {source: avatarSource, type: isWorkspaceActor ? CONST.ICON_TYPE_WORKSPACE : CONST.ICON_TYPE_AVATAR, name: primaryDisplayName, id: isWorkspaceActor ? '' : actorAccountID};
diff --git a/src/pages/home/report/ReportActionItemThread.js b/src/pages/home/report/ReportActionItemThread.js
index 9c688911759e..8d4b76a3c508 100644
--- a/src/pages/home/report/ReportActionItemThread.js
+++ b/src/pages/home/report/ReportActionItemThread.js
@@ -1,15 +1,15 @@
-import React from 'react';
-import {View, Text} from 'react-native';
import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
-import * as Report from '../../../libs/actions/Report';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import CONST from '../../../CONST';
-import avatarPropTypes from '../../../components/avatarPropTypes';
-import MultipleAvatars from '../../../components/MultipleAvatars';
-import compose from '../../../libs/compose';
-import PressableWithSecondaryInteraction from '../../../components/PressableWithSecondaryInteraction';
+import React from 'react';
+import {Text, View} from 'react-native';
+import avatarPropTypes from '@components/avatarPropTypes';
+import MultipleAvatars from '@components/MultipleAvatars';
+import PressableWithSecondaryInteraction from '@components/PressableWithSecondaryInteraction';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
const propTypes = {
/** List of participant icons for the thread */
diff --git a/src/pages/home/report/ReportActionsList.js b/src/pages/home/report/ReportActionsList.js
index 3cdd8ece876f..9549513ed368 100644
--- a/src/pages/home/report/ReportActionsList.js
+++ b/src/pages/home/report/ReportActionsList.js
@@ -1,29 +1,29 @@
+import {useRoute} from '@react-navigation/native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import Animated, {useAnimatedStyle, useSharedValue, withTiming} from 'react-native-reanimated';
import _ from 'underscore';
-import {useRoute} from '@react-navigation/native';
-import lodashGet from 'lodash/get';
-import CONST from '../../../CONST';
-import InvertedFlatList from '../../../components/InvertedFlatList';
-import {withPersonalDetails} from '../../../components/OnyxProvider';
-import ReportActionsSkeletonView from '../../../components/ReportActionsSkeletonView';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../../components/withCurrentUserPersonalDetails';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import useLocalize from '../../../hooks/useLocalize';
-import useNetwork from '../../../hooks/useNetwork';
-import useReportScrollManager from '../../../hooks/useReportScrollManager';
-import DateUtils from '../../../libs/DateUtils';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import * as Report from '../../../libs/actions/Report';
-import compose from '../../../libs/compose';
-import styles from '../../../styles/styles';
-import variables from '../../../styles/variables';
-import reportPropTypes from '../../reportPropTypes';
+import InvertedFlatList from '@components/InvertedFlatList';
+import {withPersonalDetails} from '@components/OnyxProvider';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useReportScrollManager from '@hooks/useReportScrollManager';
+import compose from '@libs/compose';
+import DateUtils from '@libs/DateUtils';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
import FloatingMessageCounter from './FloatingMessageCounter';
-import ReportActionsListItemRenderer from './ReportActionsListItemRenderer';
+import ListBoundaryLoader from './ListBoundaryLoader/ListBoundaryLoader';
import reportActionPropTypes from './reportActionPropTypes';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
+import ReportActionsListItemRenderer from './ReportActionsListItemRenderer';
const propTypes = {
/** The report currently being looked at */
@@ -36,10 +36,13 @@ const propTypes = {
mostRecentIOUReportActionID: PropTypes.string,
/** The report metadata loading states */
- isLoadingReportActions: PropTypes.bool,
+ isLoadingInitialReportActions: PropTypes.bool,
/** Are we loading more report actions? */
- isLoadingMoreReportActions: PropTypes.bool,
+ isLoadingOlderReportActions: PropTypes.bool,
+
+ /** Are we loading newer report actions? */
+ isLoadingNewerReportActions: PropTypes.bool,
/** Callback executed on list layout */
onLayout: PropTypes.func.isRequired,
@@ -48,7 +51,10 @@ const propTypes = {
onScroll: PropTypes.func,
/** Function to load more chats */
- loadMoreChats: PropTypes.func.isRequired,
+ loadOlderChats: PropTypes.func.isRequired,
+
+ /** Function to load newer chats */
+ loadNewerChats: PropTypes.func.isRequired,
/** The policy object for the current route */
policy: PropTypes.shape({
@@ -67,8 +73,9 @@ const defaultProps = {
personalDetails: {},
onScroll: () => {},
mostRecentIOUReportActionID: '',
- isLoadingReportActions: false,
- isLoadingMoreReportActions: false,
+ isLoadingInitialReportActions: false,
+ isLoadingOlderReportActions: false,
+ isLoadingNewerReportActions: false,
...withCurrentUserPersonalDetailsDefaultProps,
};
@@ -107,8 +114,9 @@ function isMessageUnread(message, lastReadTime) {
function ReportActionsList({
report,
- isLoadingReportActions,
- isLoadingMoreReportActions,
+ isLoadingInitialReportActions,
+ isLoadingOlderReportActions,
+ isLoadingNewerReportActions,
sortedReportActions,
windowHeight,
onScroll,
@@ -117,7 +125,8 @@ function ReportActionsList({
personalDetailsList,
currentUserPersonalDetails,
hasOutstandingIOU,
- loadMoreChats,
+ loadNewerChats,
+ loadOlderChats,
onLayout,
isComposerFullSize,
}) {
@@ -130,8 +139,9 @@ function ReportActionsList({
const [currentUnreadMarker, setCurrentUnreadMarker] = useState(null);
const scrollingVerticalOffset = useRef(0);
const readActionSkipped = useRef(false);
+ const hasHeaderRendered = useRef(false);
+ const hasFooterRendered = useRef(false);
const reportActionSize = useRef(sortedReportActions.length);
- const firstRenderRef = useRef(true);
const linkedReportActionID = lodashGet(route, 'params.reportActionID', '');
// This state is used to force a re-render when the user manually marks a message as unread
@@ -342,28 +352,30 @@ function ReportActionsList({
const hideComposer = ReportUtils.shouldDisableWriteActions(report);
const shouldShowReportRecipientLocalTime = ReportUtils.canShowReportRecipientLocalTime(personalDetailsList, report, currentUserPersonalDetails.accountID) && !isComposerFullSize;
- const renderFooter = useCallback(() => {
+ const contentContainerStyle = useMemo(
+ () => [styles.chatContentScrollView, isLoadingNewerReportActions ? styles.chatContentScrollViewWithHeaderLoader : {}],
+ [isLoadingNewerReportActions],
+ );
+
+ const lastReportAction = useMemo(() => _.last(sortedReportActions) || {}, [sortedReportActions]);
+
+ const listFooterComponent = useCallback(() => {
// Skip this hook on the first render, as we are not sure if more actions are going to be loaded
// Therefore showing the skeleton on footer might be misleading
- if (firstRenderRef.current) {
- firstRenderRef.current = false;
+ if (!hasFooterRendered.current) {
+ hasFooterRendered.current = true;
return null;
}
- if (isLoadingMoreReportActions) {
- return ;
- }
-
- // Make sure the oldest report action loaded is not the first. This is so we do not show the
- // skeleton view above the created action in a newly generated optimistic chat or one with not
- // that many comments.
- const lastReportAction = _.last(sortedReportActions) || {};
- if (isLoadingReportActions && lastReportAction.actionName !== CONST.REPORT.ACTIONS.TYPE.CREATED) {
- return ;
- }
-
- return null;
- }, [isLoadingMoreReportActions, isLoadingReportActions, sortedReportActions, isOffline]);
+ return (
+
+ );
+ }, [isLoadingInitialReportActions, isLoadingOlderReportActions, lastReportAction.actionName]);
const onLayoutInner = useCallback(
(event) => {
@@ -372,6 +384,19 @@ function ReportActionsList({
[onLayout],
);
+ const listHeaderComponent = useCallback(() => {
+ if (!hasHeaderRendered.current) {
+ hasHeaderRendered.current = true;
+ return null;
+ }
+ return (
+
+ );
+ }, [isLoadingNewerReportActions]);
+
return (
<>
0);
+ const isFirstRender = useRef(true);
+ const hasCachedActions = useInitialValue(() => _.size(props.reportActions) > 0);
+ const mostRecentIOUReportActionID = useInitialValue(() => ReportActionsUtils.getMostRecentIOURequestActionID(props.reportActions));
- const mostRecentIOUReportActionID = useRef(ReportActionsUtils.getMostRecentIOURequestActionID(props.reportActions));
const prevNetworkRef = useRef(props.network);
const prevIsSmallScreenWidthRef = useRef(props.isSmallScreenWidth);
@@ -142,9 +148,9 @@ function ReportActionsView(props) {
* Retrieves the next set of report actions for the chat once we are nearing the end of what we are currently
* displaying.
*/
- const loadMoreChats = () => {
+ const loadOlderChats = () => {
// Only fetch more if we are not already fetching so that we don't initiate duplicate requests.
- if (props.isLoadingMoreReportActions) {
+ if (props.isLoadingOlderReportActions) {
return;
}
@@ -154,11 +160,42 @@ function ReportActionsView(props) {
if (oldestReportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED) {
return;
}
-
// Retrieve the next REPORT.ACTIONS.LIMIT sized page of comments
- Report.readOldestAction(reportID, oldestReportAction.reportActionID);
+ Report.getOlderActions(reportID, oldestReportAction.reportActionID);
};
+ /**
+ * Retrieves the next set of report actions for the chat once we are nearing the end of what we are currently
+ * displaying.
+ */
+ const loadNewerChats = useMemo(
+ () =>
+ _.throttle(({distanceFromStart}) => {
+ if (props.isLoadingNewerReportActions || props.isLoadingInitialReportActions) {
+ return;
+ }
+
+ // Ideally, we wouldn't need to use the 'distanceFromStart' variable. However, due to the low value set for 'maxToRenderPerBatch',
+ // the component undergoes frequent re-renders. This frequent re-rendering triggers the 'onStartReached' callback multiple times.
+ //
+ // To mitigate this issue, we use 'CONST.CHAT_HEADER_LOADER_HEIGHT' as a threshold. This ensures that 'onStartReached' is not
+ // triggered unnecessarily when the chat is initially opened or when the user has reached the end of the list but hasn't scrolled further.
+ //
+ // Additionally, we use throttling on the 'onStartReached' callback to further reduce the frequency of its invocation.
+ // This should be removed once the issue of frequent re-renders is resolved.
+ //
+ // onStartReached is triggered during the first render. Since we use OpenReport on the first render and are confident about the message ordering, we can safely skip this call
+ if (isFirstRender.current || distanceFromStart <= CONST.CHAT_HEADER_LOADER_HEIGHT) {
+ isFirstRender.current = false;
+ return;
+ }
+
+ const newestReportAction = _.first(props.reportActions);
+ Report.getNewerActions(reportID, newestReportAction.reportActionID);
+ }, 500),
+ [props.isLoadingNewerReportActions, props.isLoadingInitialReportActions, props.reportActions, reportID],
+ );
+
/**
* Runs when the FlatList finishes laying out
*/
@@ -168,7 +205,7 @@ function ReportActionsView(props) {
}
didLayout.current = true;
- Timing.end(CONST.TIMING.SWITCH_REPORT, hasCachedActions.current ? CONST.TIMING.WARM : CONST.TIMING.COLD);
+ Timing.end(CONST.TIMING.SWITCH_REPORT, hasCachedActions ? CONST.TIMING.WARM : CONST.TIMING.COLD);
// Capture the init measurement only once not per each chat switch as the value gets overwritten
if (!ReportActionsView.initMeasured) {
@@ -190,10 +227,12 @@ function ReportActionsView(props) {
report={props.report}
onLayout={recordTimeToMeasureItemLayout}
sortedReportActions={props.reportActions}
- mostRecentIOUReportActionID={mostRecentIOUReportActionID.current}
- isLoadingReportActions={props.isLoadingReportActions}
- isLoadingMoreReportActions={props.isLoadingMoreReportActions}
- loadMoreChats={loadMoreChats}
+ mostRecentIOUReportActionID={mostRecentIOUReportActionID}
+ loadOlderChats={loadOlderChats}
+ loadNewerChats={loadNewerChats}
+ isLoadingInitialReportActions={props.isLoadingInitialReportActions}
+ isLoadingOlderReportActions={props.isLoadingOlderReportActions}
+ isLoadingNewerReportActions={props.isLoadingNewerReportActions}
policy={props.policy}
/>
@@ -222,11 +261,15 @@ function arePropsEqual(oldProps, newProps) {
return false;
}
- if (oldProps.isLoadingMoreReportActions !== newProps.isLoadingMoreReportActions) {
+ if (oldProps.isLoadingInitialReportActions !== newProps.isLoadingInitialReportActions) {
+ return false;
+ }
+
+ if (oldProps.isLoadingOlderReportActions !== newProps.isLoadingOlderReportActions) {
return false;
}
- if (oldProps.isLoadingReportActions !== newProps.isLoadingReportActions) {
+ if (oldProps.isLoadingNewerReportActions !== newProps.isLoadingNewerReportActions) {
return false;
}
diff --git a/src/pages/home/report/ReportAttachments.js b/src/pages/home/report/ReportAttachments.js
index 5f194d10bce3..173a4b5637be 100644
--- a/src/pages/home/report/ReportAttachments.js
+++ b/src/pages/home/report/ReportAttachments.js
@@ -1,10 +1,10 @@
-import React from 'react';
-import _ from 'underscore';
import PropTypes from 'prop-types';
-import AttachmentModal from '../../../components/AttachmentModal';
-import Navigation from '../../../libs/Navigation/Navigation';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import ROUTES from '../../../ROUTES';
+import React, {useCallback} from 'react';
+import _ from 'underscore';
+import AttachmentModal from '@components/AttachmentModal';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Navigation route context info provided by react navigation */
@@ -24,6 +24,14 @@ function ReportAttachments(props) {
const report = ReportUtils.getReport(reportID);
const source = decodeURI(_.get(props, ['route', 'params', 'source']));
+ const onCarouselAttachmentChange = useCallback(
+ (attachment) => {
+ const route = ROUTES.REPORT_ATTACHMENTS.getRoute(reportID, attachment.source);
+ Navigation.navigate(route);
+ },
+ [reportID],
+ );
+
return (
Navigation.dismissModal()}
- onCarouselAttachmentChange={(attachment) => {
- const route = ROUTES.REPORT_ATTACHMENTS.getRoute(reportID, attachment.source);
- Navigation.navigate(route);
- }}
+ onCarouselAttachmentChange={onCarouselAttachmentChange}
/>
);
}
diff --git a/src/pages/home/report/ReportAttachmentsContext.js b/src/pages/home/report/ReportAttachmentsContext.js
index a51df01313e5..5602612a6cd6 100644
--- a/src/pages/home/report/ReportAttachmentsContext.js
+++ b/src/pages/home/report/ReportAttachmentsContext.js
@@ -1,6 +1,6 @@
-import React, {useEffect, useMemo, useRef} from 'react';
import PropTypes from 'prop-types';
-import useCurrentReportID from '../../../hooks/useCurrentReportID';
+import React, {useEffect, useMemo, useRef} from 'react';
+import useCurrentReportID from '@hooks/useCurrentReportID';
const ReportAttachmentsContext = React.createContext();
diff --git a/src/pages/home/report/ReportDetailsShareCodePage.js b/src/pages/home/report/ReportDetailsShareCodePage.js
index 7c22726ac82b..0ef2d46029ea 100644
--- a/src/pages/home/report/ReportDetailsShareCodePage.js
+++ b/src/pages/home/report/ReportDetailsShareCodePage.js
@@ -1,7 +1,7 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import reportPropTypes from '../../reportPropTypes';
-import ShareCodePage from '../../ShareCodePage';
+import React from 'react';
+import reportPropTypes from '@pages/reportPropTypes';
+import ShareCodePage from '@pages/ShareCodePage';
import withReportOrNotFound from './withReportOrNotFound';
const propTypes = {
diff --git a/src/pages/home/report/ReportDropUI.js b/src/pages/home/report/ReportDropUI.js
index d742346cd769..ae0c941b37e7 100644
--- a/src/pages/home/report/ReportDropUI.js
+++ b/src/pages/home/report/ReportDropUI.js
@@ -1,12 +1,12 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
-import Text from '../../../components/Text';
-import DragAndDropConsumer from '../../../components/DragAndDrop/Consumer';
-import Icon from '../../../components/Icon';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import useLocalize from '../../../hooks/useLocalize';
+import DragAndDropConsumer from '@components/DragAndDrop/Consumer';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
const propTypes = {
/** Callback to execute when a file is dropped. */
diff --git a/src/pages/home/report/ReportFooter.js b/src/pages/home/report/ReportFooter.js
index 2237e6448504..f3598a92a9eb 100644
--- a/src/pages/home/report/ReportFooter.js
+++ b/src/pages/home/report/ReportFooter.js
@@ -1,24 +1,24 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import {View, Keyboard} from 'react-native';
-import CONST from '../../../CONST';
+import AnonymousReportFooter from '@components/AnonymousReportFooter';
+import ArchivedReportFooter from '@components/ArchivedReportFooter';
+import OfflineIndicator from '@components/OfflineIndicator';
+import participantPropTypes from '@components/participantPropTypes';
+import SwipeableView from '@components/SwipeableView';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useNetwork from '@hooks/useNetwork';
+import compose from '@libs/compose';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import ReportActionCompose from './ReportActionCompose/ReportActionCompose';
-import AnonymousReportFooter from '../../../components/AnonymousReportFooter';
-import SwipeableView from '../../../components/SwipeableView';
-import OfflineIndicator from '../../../components/OfflineIndicator';
-import ArchivedReportFooter from '../../../components/ArchivedReportFooter';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import useNetwork from '../../../hooks/useNetwork';
-import styles from '../../../styles/styles';
-import variables from '../../../styles/variables';
import reportActionPropTypes from './reportActionPropTypes';
-import reportPropTypes from '../../reportPropTypes';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import * as Session from '../../../libs/actions/Session';
-import participantPropTypes from '../../../components/participantPropTypes';
const propTypes = {
/** Report object for the current report */
diff --git a/src/pages/home/report/ReportTypingIndicator.js b/src/pages/home/report/ReportTypingIndicator.js
index db97f712d65f..7b2b46b7d097 100755
--- a/src/pages/home/report/ReportTypingIndicator.js
+++ b/src/pages/home/report/ReportTypingIndicator.js
@@ -1,16 +1,16 @@
-import React, {useMemo} from 'react';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React, {useMemo} from 'react';
import {withOnyx} from 'react-native-onyx';
-import {withNetwork} from '../../../components/OnyxProvider';
-import networkPropTypes from '../../../components/networkPropTypes';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
-import styles from '../../../styles/styles';
-import * as PersonalDetails from '../../../libs/actions/PersonalDetails';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Text from '../../../components/Text';
-import TextWithEllipsis from '../../../components/TextWithEllipsis';
+import _ from 'underscore';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import Text from '@components/Text';
+import TextWithEllipsis from '@components/TextWithEllipsis';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Key-value pairs of user accountIDs/logins and whether or not they are typing. Keys are accountIDs or logins. */
diff --git a/src/pages/home/report/withReportAndReportActionOrNotFound.js b/src/pages/home/report/withReportAndReportActionOrNotFound.js
index b4346504b327..1450ab3fd10a 100644
--- a/src/pages/home/report/withReportAndReportActionOrNotFound.js
+++ b/src/pages/home/report/withReportAndReportActionOrNotFound.js
@@ -1,19 +1,19 @@
import PropTypes from 'prop-types';
-import React, {useEffect, useCallback} from 'react';
+import React, {useCallback, useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import getComponentDisplayName from '../../../libs/getComponentDisplayName';
-import NotFoundPage from '../../ErrorPage/NotFoundPage';
-import ONYXKEYS from '../../../ONYXKEYS';
-import reportPropTypes from '../../reportPropTypes';
-import reportMetadataPropTypes from '../../reportMetadataPropTypes';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import withWindowDimensions from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import reportMetadataPropTypes from '@pages/reportMetadataPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import * as Report from '@userActions/Report';
+import ONYXKEYS from '@src/ONYXKEYS';
import reportActionPropTypes from './reportActionPropTypes';
-import FullscreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
-import * as Report from '../../../libs/actions/Report';
-import compose from '../../../libs/compose';
-import withWindowDimensions from '../../../components/withWindowDimensions';
export default function (WrappedComponent) {
const propTypes = {
@@ -67,8 +67,9 @@ export default function (WrappedComponent) {
reportActions: {},
report: {},
reportMetadata: {
- isLoadingReportActions: false,
- isLoadingMoreReportActions: false,
+ isLoadingInitialReportActions: false,
+ isLoadingOlderReportActions: false,
+ isLoadingNewerReportActions: false,
},
policies: {},
betas: [],
@@ -102,7 +103,7 @@ export default function (WrappedComponent) {
// Perform all the loading checks
const isLoadingReport = props.isLoadingReportData && (_.isEmpty(props.report) || !props.report.reportID);
- const isLoadingReportAction = _.isEmpty(props.reportActions) || (props.reportMetadata.isLoadingReportActions && _.isEmpty(getReportAction()));
+ const isLoadingReportAction = _.isEmpty(props.reportActions) || (props.reportMetadata.isLoadingInitialReportActions && _.isEmpty(getReportAction()));
const shouldHideReport = !isLoadingReport && (_.isEmpty(props.report) || !props.report.reportID || !ReportUtils.canAccessReport(props.report, props.policies, props.betas));
if ((isLoadingReport || isLoadingReportAction) && !shouldHideReport) {
@@ -129,7 +130,7 @@ export default function (WrappedComponent) {
WithReportAndReportActionOrNotFound.displayName = `withReportAndReportActionOrNotFound(${getComponentDisplayName(WrappedComponent)})`;
// eslint-disable-next-line rulesdir/no-negated-variables
- const withReportAndReportActionOrNotFound = React.forwardRef((props, ref) => (
+ const WithReportAndReportActionOrNotFoundWithRef = React.forwardRef((props, ref) => (
));
+ WithReportAndReportActionOrNotFoundWithRef.displayName = 'WithReportAndReportActionOrNotFoundWithRef';
+
return compose(
withWindowDimensions,
withOnyx({
@@ -160,5 +163,5 @@ export default function (WrappedComponent) {
canEvict: false,
},
}),
- )(withReportAndReportActionOrNotFound);
+ )(WithReportAndReportActionOrNotFoundWithRef);
}
diff --git a/src/pages/home/report/withReportOrNotFound.js b/src/pages/home/report/withReportOrNotFound.js
deleted file mode 100644
index 891e2e2418c6..000000000000
--- a/src/pages/home/report/withReportOrNotFound.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import {withOnyx} from 'react-native-onyx';
-import _ from 'underscore';
-import getComponentDisplayName from '../../../libs/getComponentDisplayName';
-import NotFoundPage from '../../ErrorPage/NotFoundPage';
-import ONYXKEYS from '../../../ONYXKEYS';
-import reportPropTypes from '../../reportPropTypes';
-import FullscreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator';
-import * as ReportUtils from '../../../libs/ReportUtils';
-
-export default function (shouldRequireReportID = true) {
- const propTypes = {
- /** The HOC takes an optional ref as a prop and passes it as a ref to the wrapped component.
- * That way, if a ref is passed to a component wrapped in the HOC, the ref is a reference to the wrapped component, not the HOC. */
- forwardedRef: PropTypes.func,
-
- /** The report currently being looked at */
- report: reportPropTypes,
-
- /** The policies which the user has access to */
- policies: PropTypes.objectOf(
- PropTypes.shape({
- /** The policy name */
- name: PropTypes.string,
-
- /** The type of the policy */
- type: PropTypes.string,
- }),
- ),
-
- /** Route params */
- route: PropTypes.shape({
- params: PropTypes.shape({
- /** Report ID passed via route */
- reportID: PropTypes.string,
- }),
- }).isRequired,
-
- /** Beta features list */
- betas: PropTypes.arrayOf(PropTypes.string),
-
- /** Indicated whether the report data is loading */
- isLoadingReportData: PropTypes.bool,
- };
-
- const defaultProps = {
- forwardedRef: () => {},
- report: {},
- policies: {},
- betas: [],
- isLoadingReportData: true,
- };
-
- return (WrappedComponent) => {
- // eslint-disable-next-line rulesdir/no-negated-variables
- function WithReportOrNotFound(props) {
- const contentShown = React.useRef(false);
-
- const isReportIdInRoute = !_.isUndefined(props.route.params.reportID);
-
- // If we should require reportID or we have a reportID in the route, we will check the reportID is valid or not
- if (shouldRequireReportID || isReportIdInRoute) {
- const shouldShowFullScreenLoadingIndicator = props.isLoadingReportData && (_.isEmpty(props.report) || !props.report.reportID);
- // eslint-disable-next-line rulesdir/no-negated-variables
- const shouldShowNotFoundPage = _.isEmpty(props.report) || !props.report.reportID || !ReportUtils.canAccessReport(props.report, props.policies, props.betas);
-
- // If the content was shown but it's not anymore that means the report was deleted and we are probably navigating out of this screen.
- // Return null for this case to avoid rendering FullScreenLoadingIndicator or NotFoundPage when animating transition.
- if (shouldShowNotFoundPage && contentShown.current) {
- return null;
- }
-
- if (shouldShowFullScreenLoadingIndicator) {
- return ;
- }
-
- if (shouldShowNotFoundPage) {
- return ;
- }
- }
-
- if (!contentShown.current) {
- contentShown.current = true;
- }
-
- const rest = _.omit(props, ['forwardedRef']);
- return (
-
- );
- }
-
- WithReportOrNotFound.propTypes = propTypes;
- WithReportOrNotFound.defaultProps = defaultProps;
- WithReportOrNotFound.displayName = `withReportOrNotFound(${getComponentDisplayName(WrappedComponent)})`;
-
- // eslint-disable-next-line rulesdir/no-negated-variables
- const withReportOrNotFound = React.forwardRef((props, ref) => (
-
- ));
-
- return withOnyx({
- report: {
- key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
- },
- isLoadingReportData: {
- key: ONYXKEYS.IS_LOADING_REPORT_DATA,
- },
- betas: {
- key: ONYXKEYS.BETAS,
- },
- policies: {
- key: ONYXKEYS.COLLECTION.POLICY,
- },
- })(withReportOrNotFound);
- };
-}
diff --git a/src/pages/home/report/withReportOrNotFound.tsx b/src/pages/home/report/withReportOrNotFound.tsx
new file mode 100644
index 000000000000..81d1376abd37
--- /dev/null
+++ b/src/pages/home/report/withReportOrNotFound.tsx
@@ -0,0 +1,89 @@
+/* eslint-disable rulesdir/no-negated-variables */
+import {RouteProp} from '@react-navigation/native';
+import React, {ComponentType, ForwardedRef, RefAttributes} from 'react';
+import {OnyxEntry, withOnyx} from 'react-native-onyx';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import * as ReportUtils from '@libs/ReportUtils';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import ONYXKEYS from '@src/ONYXKEYS';
+import * as OnyxTypes from '@src/types/onyx';
+
+type OnyxProps = {
+ /** The report currently being looked at */
+ report: OnyxEntry;
+ /** The policies which the user has access to */
+ policies: OnyxEntry;
+ /** Beta features list */
+ betas: OnyxEntry;
+ /** Indicated whether the report data is loading */
+ isLoadingReportData: OnyxEntry;
+};
+
+type ComponentProps = OnyxProps & {
+ route: RouteProp<{params: {reportID: string}}>;
+};
+
+export default function (
+ shouldRequireReportID = true,
+): (
+ WrappedComponent: React.ComponentType>,
+) => React.ComponentType, keyof OnyxProps>> {
+ return function (WrappedComponent: ComponentType>) {
+ function WithReportOrNotFound(props: TProps, ref: ForwardedRef) {
+ const contentShown = React.useRef(false);
+
+ const isReportIdInRoute = props.route.params.reportID?.length;
+
+ if (shouldRequireReportID || isReportIdInRoute) {
+ const shouldShowFullScreenLoadingIndicator = props.isLoadingReportData && (!Object.entries(props.report ?? {}).length || !props.report?.reportID);
+
+ const shouldShowNotFoundPage =
+ !Object.entries(props.report ?? {}).length || !props.report?.reportID || !ReportUtils.canAccessReport(props.report, props.policies, props.betas, {});
+
+ // If the content was shown but it's not anymore that means the report was deleted and we are probably navigating out of this screen.
+ // Return null for this case to avoid rendering FullScreenLoadingIndicator or NotFoundPage when animating transition.
+ if (shouldShowNotFoundPage && contentShown.current) {
+ return null;
+ }
+
+ if (shouldShowFullScreenLoadingIndicator) {
+ return ;
+ }
+
+ if (shouldShowNotFoundPage) {
+ return ;
+ }
+ }
+
+ if (!contentShown.current) {
+ contentShown.current = true;
+ }
+
+ return (
+
+ );
+ }
+
+ WithReportOrNotFound.displayName = `withReportOrNotFound(${getComponentDisplayName(WrappedComponent)})`;
+
+ return withOnyx, OnyxProps>({
+ report: {
+ key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
+ },
+ isLoadingReportData: {
+ key: ONYXKEYS.IS_LOADING_REPORT_DATA,
+ },
+ betas: {
+ key: ONYXKEYS.BETAS,
+ },
+ policies: {
+ key: ONYXKEYS.COLLECTION.POLICY,
+ },
+ })(React.forwardRef(WithReportOrNotFound));
+ };
+}
diff --git a/src/pages/home/sidebar/AvatarWithOptionalStatus.js b/src/pages/home/sidebar/AvatarWithOptionalStatus.js
index adf9cdda5cd0..b456788224fb 100644
--- a/src/pages/home/sidebar/AvatarWithOptionalStatus.js
+++ b/src/pages/home/sidebar/AvatarWithOptionalStatus.js
@@ -1,15 +1,15 @@
/* eslint-disable rulesdir/onyx-props-must-have-default */
+import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback';
-import Text from '../../../components/Text';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import PressableAvatarWithIndicator from './PressableAvatarWithIndicator';
-import Navigation from '../../../libs/Navigation/Navigation';
-import useLocalize from '../../../hooks/useLocalize';
-import styles from '../../../styles/styles';
-import ROUTES from '../../../ROUTES';
-import CONST from '../../../CONST';
const propTypes = {
/** Whether the create menu is open or not */
diff --git a/src/pages/home/sidebar/GlobalNavigation/GlobalNavigationMenuItem.js b/src/pages/home/sidebar/GlobalNavigation/GlobalNavigationMenuItem.js
index d24960e80ff2..93355fcfd530 100644
--- a/src/pages/home/sidebar/GlobalNavigation/GlobalNavigationMenuItem.js
+++ b/src/pages/home/sidebar/GlobalNavigation/GlobalNavigationMenuItem.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from '../../../../components/Text';
-import styles from '../../../../styles/styles';
-import * as StyleUtils from '../../../../styles/StyleUtils';
-import Icon from '../../../../components/Icon';
-import CONST from '../../../../CONST';
-import variables from '../../../../styles/variables';
-import PressableWithFeedback from '../../../../components/Pressable/PressableWithFeedback';
+import Icon from '@components/Icon';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
+import CONST from '@src/CONST';
const propTypes = {
/** Icon to display */
diff --git a/src/pages/home/sidebar/GlobalNavigation/index.js b/src/pages/home/sidebar/GlobalNavigation/index.js
index 1a8e923d1ff6..569ebf6fd0a8 100644
--- a/src/pages/home/sidebar/GlobalNavigation/index.js
+++ b/src/pages/home/sidebar/GlobalNavigation/index.js
@@ -1,15 +1,15 @@
-import React, {useMemo, useContext} from 'react';
+import React, {useContext, useMemo} from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import styles from '../../../../styles/styles';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import CONST from '../../../../CONST';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ROUTES from '../../../../ROUTES';
-import useLocalize from '../../../../hooks/useLocalize';
+import * as Expensicons from '@components/Icon/Expensicons';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import {SidebarNavigationContext} from '@pages/home/sidebar/SidebarNavigationContext';
+import SignInOrAvatarWithOptionalStatus from '@pages/home/sidebar/SignInOrAvatarWithOptionalStatus';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import GlobalNavigationMenuItem from './GlobalNavigationMenuItem';
-import {SidebarNavigationContext} from '../SidebarNavigationContext';
-import SignInOrAvatarWithOptionalStatus from '../SignInOrAvatarWithOptionalStatus';
function GlobalNavigation() {
const sidebarNavigation = useContext(SidebarNavigationContext);
diff --git a/src/pages/home/sidebar/PressableAvatarWithIndicator.js b/src/pages/home/sidebar/PressableAvatarWithIndicator.js
index 7b240c108e4e..e798bece339f 100644
--- a/src/pages/home/sidebar/PressableAvatarWithIndicator.js
+++ b/src/pages/home/sidebar/PressableAvatarWithIndicator.js
@@ -1,17 +1,17 @@
/* eslint-disable rulesdir/onyx-props-must-have-default */
import lodashGet from 'lodash/get';
-import React, {useCallback} from 'react';
import PropTypes from 'prop-types';
-import withCurrentUserPersonalDetails from '../../../components/withCurrentUserPersonalDetails';
-import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback';
-import AvatarWithIndicator from '../../../components/AvatarWithIndicator';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import Navigation from '../../../libs/Navigation/Navigation';
-import * as UserUtils from '../../../libs/UserUtils';
-import useLocalize from '../../../hooks/useLocalize';
-import ROUTES from '../../../ROUTES';
-import CONST from '../../../CONST';
-import personalDetailsPropType from '../../personalDetailsPropType';
+import React, {useCallback} from 'react';
+import AvatarWithIndicator from '@components/AvatarWithIndicator';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as UserUtils from '@libs/UserUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Whether the create menu is open or not */
diff --git a/src/pages/home/sidebar/SidebarLinks.js b/src/pages/home/sidebar/SidebarLinks.js
index d3ff3070466f..0e7d6aa38545 100644
--- a/src/pages/home/sidebar/SidebarLinks.js
+++ b/src/pages/home/sidebar/SidebarLinks.js
@@ -1,31 +1,31 @@
/* eslint-disable rulesdir/onyx-props-must-have-default */
-import React, {useEffect, useRef, useCallback} from 'react';
-import {View, InteractionManager} from 'react-native';
-import _ from 'underscore';
import PropTypes from 'prop-types';
-import styles from '../../../styles/styles';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import ONYXKEYS from '../../../ONYXKEYS';
-import safeAreaInsetPropTypes from '../../safeAreaInsetPropTypes';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import Icon from '../../../components/Icon';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import Tooltip from '../../../components/Tooltip';
-import CONST from '../../../CONST';
-import * as App from '../../../libs/actions/App';
-import LHNOptionsList from '../../../components/LHNOptionsList/LHNOptionsList';
-import SidebarUtils from '../../../libs/SidebarUtils';
-import Header from '../../../components/Header';
-import OptionsListSkeletonView from '../../../components/OptionsListSkeletonView';
-import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback';
-import * as Session from '../../../libs/actions/Session';
-import KeyboardShortcut from '../../../libs/KeyboardShortcut';
-import onyxSubscribe from '../../../libs/onyxSubscribe';
-import * as ReportActionContextMenu from '../report/ContextMenu/ReportActionContextMenu';
-import Text from '../../../components/Text';
-import useLocalize from '../../../hooks/useLocalize';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
+import React, {useCallback, useEffect, useRef} from 'react';
+import {InteractionManager, View} from 'react-native';
+import _ from 'underscore';
+import Header from '@components/Header';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import LHNOptionsList from '@components/LHNOptionsList/LHNOptionsList';
+import OptionsListSkeletonView from '@components/OptionsListSkeletonView';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import KeyboardShortcut from '@libs/KeyboardShortcut';
+import Navigation from '@libs/Navigation/Navigation';
+import onyxSubscribe from '@libs/onyxSubscribe';
+import SidebarUtils from '@libs/SidebarUtils';
+import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
+import safeAreaInsetPropTypes from '@pages/safeAreaInsetPropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as App from '@userActions/App';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const basePropTypes = {
/** Safe area insets required for mobile devices margins */
diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js
index 394f6c5ddc5a..a5d58768a95d 100644
--- a/src/pages/home/sidebar/SidebarLinksData.js
+++ b/src/pages/home/sidebar/SidebarLinksData.js
@@ -1,21 +1,21 @@
-import React, {useCallback, useMemo, useRef} from 'react';
-import _ from 'underscore';
import {deepEqual} from 'fast-equals';
-import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useMemo, useRef} from 'react';
import {View} from 'react-native';
-import SidebarUtils from '../../../libs/SidebarUtils';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import withCurrentReportID from '@components/withCurrentReportID';
+import withNavigationFocus from '@components/withNavigationFocus';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as SessionUtils from '@libs/SessionUtils';
+import SidebarUtils from '@libs/SidebarUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import SidebarLinks, {basePropTypes} from './SidebarLinks';
-import withCurrentReportID from '../../../components/withCurrentReportID';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
-import reportPropTypes from '../../reportPropTypes';
-import CONST from '../../../CONST';
-import useLocalize from '../../../hooks/useLocalize';
-import styles from '../../../styles/styles';
-import withNavigationFocus from '../../../components/withNavigationFocus';
-import * as SessionUtils from '../../../libs/SessionUtils';
const propTypes = {
...basePropTypes,
diff --git a/src/pages/home/sidebar/SidebarNavigationContext.js b/src/pages/home/sidebar/SidebarNavigationContext.js
index 47bda74e052d..d39c24178f8d 100644
--- a/src/pages/home/sidebar/SidebarNavigationContext.js
+++ b/src/pages/home/sidebar/SidebarNavigationContext.js
@@ -1,9 +1,9 @@
-import React, {useMemo, useCallback, useState} from 'react';
import PropTypes from 'prop-types';
+import React, {useCallback, useMemo, useState} from 'react';
import _ from 'underscore';
-import CONST from '../../../CONST';
-import Navigation from '../../../libs/Navigation/Navigation';
-import GLOBAL_NAVIGATION_MAPPING from '../../../GLOBAL_NAVIGATION_MAPPING';
+import Navigation from '@libs/Navigation/Navigation';
+import CONST from '@src/CONST';
+import GLOBAL_NAVIGATION_MAPPING from '@src/GLOBAL_NAVIGATION_MAPPING';
const propTypes = {
/** Children to wrap. The part of app that should have acces to this context */
diff --git a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js
index 97f1f7eaee20..cd8bff2e5945 100644
--- a/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js
+++ b/src/pages/home/sidebar/SidebarScreen/BaseSidebarScreen.js
@@ -1,14 +1,14 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import styles from '../../../../styles/styles';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import Timing from '../../../../libs/actions/Timing';
-import CONST from '../../../../CONST';
-import Performance from '../../../../libs/Performance';
-import * as Browser from '../../../../libs/Browser';
-import GlobalNavigation from '../GlobalNavigation';
-import SubNavigation from '../SubNavigation/SubNavigation';
+import ScreenWrapper from '@components/ScreenWrapper';
+import * as Browser from '@libs/Browser';
+import Performance from '@libs/Performance';
+import GlobalNavigation from '@pages/home/sidebar/GlobalNavigation';
+import SubNavigation from '@pages/home/sidebar/SubNavigation/SubNavigation';
+import styles from '@styles/styles';
+import Timing from '@userActions/Timing';
+import CONST from '@src/CONST';
const propTypes = {
/** Children to wrap (floating button). */
diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
index 02f1856c7bf5..045aa66cded5 100644
--- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
+++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
@@ -1,31 +1,31 @@
-import React, {useState, useEffect, useRef, useCallback, useImperativeHandle, forwardRef} from 'react';
-import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
import {View} from 'react-native';
-import styles from '../../../../styles/styles';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ROUTES from '../../../../ROUTES';
-import NAVIGATORS from '../../../../NAVIGATORS';
-import SCREENS from '../../../../SCREENS';
-import Permissions from '../../../../libs/Permissions';
-import * as Policy from '../../../../libs/actions/Policy';
-import PopoverMenu from '../../../../components/PopoverMenu';
-import CONST from '../../../../CONST';
-import FloatingActionButton from '../../../../components/FloatingActionButton';
-import compose from '../../../../libs/compose';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import withWindowDimensions from '../../../../components/withWindowDimensions';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import withNavigation from '../../../../components/withNavigation';
-import * as Welcome from '../../../../libs/actions/Welcome';
-import withNavigationFocus from '../../../../components/withNavigationFocus';
-import * as Task from '../../../../libs/actions/Task';
-import * as Session from '../../../../libs/actions/Session';
-import * as IOU from '../../../../libs/actions/IOU';
-import usePrevious from '../../../../hooks/usePrevious';
-import * as App from '../../../../libs/actions/App';
+import {withOnyx} from 'react-native-onyx';
+import FloatingActionButton from '@components/FloatingActionButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PopoverMenu from '@components/PopoverMenu';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withNavigation from '@components/withNavigation';
+import withNavigationFocus from '@components/withNavigationFocus';
+import withWindowDimensions from '@components/withWindowDimensions';
+import usePrevious from '@hooks/usePrevious';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import styles from '@styles/styles';
+import * as App from '@userActions/App';
+import * as IOU from '@userActions/IOU';
+import * as Policy from '@userActions/Policy';
+import * as Session from '@userActions/Session';
+import * as Task from '@userActions/Task';
+import * as Welcome from '@userActions/Welcome';
+import CONST from '@src/CONST';
+import NAVIGATORS from '@src/NAVIGATORS';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
/**
* @param {Object} [policy]
@@ -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()),
},
]
: []),
@@ -257,6 +257,16 @@ FloatingActionButtonAndPopover.propTypes = propTypes;
FloatingActionButtonAndPopover.defaultProps = defaultProps;
FloatingActionButtonAndPopover.displayName = 'FloatingActionButtonAndPopover';
+const FloatingActionButtonAndPopoverWithRef = forwardRef((props, ref) => (
+
+));
+
+FloatingActionButtonAndPopoverWithRef.displayName = 'FloatingActionButtonAndPopoverWithRef';
+
export default compose(
withLocalize,
withNavigation,
@@ -277,12 +287,4 @@ export default compose(
key: ONYXKEYS.DEMO_INFO,
},
}),
-)(
- forwardRef((props, ref) => (
-
- )),
-);
+)(FloatingActionButtonAndPopoverWithRef);
diff --git a/src/pages/home/sidebar/SidebarScreen/index.js b/src/pages/home/sidebar/SidebarScreen/index.js
index 53640fffe559..6f2fa1f9944a 100755
--- a/src/pages/home/sidebar/SidebarScreen/index.js
+++ b/src/pages/home/sidebar/SidebarScreen/index.js
@@ -1,8 +1,8 @@
import React, {useCallback, useRef} from 'react';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import FreezeWrapper from '@libs/Navigation/FreezeWrapper';
import BaseSidebarScreen from './BaseSidebarScreen';
import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover';
-import FreezeWrapper from '../../../../libs/Navigation/FreezeWrapper';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
function SidebarScreen(props) {
const popoverModal = useRef(null);
diff --git a/src/pages/home/sidebar/SidebarScreen/index.native.js b/src/pages/home/sidebar/SidebarScreen/index.native.js
index 35c8b876338f..bb4d08d33ea7 100755
--- a/src/pages/home/sidebar/SidebarScreen/index.native.js
+++ b/src/pages/home/sidebar/SidebarScreen/index.native.js
@@ -1,8 +1,8 @@
import React from 'react';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import FreezeWrapper from '@libs/Navigation/FreezeWrapper';
import BaseSidebarScreen from './BaseSidebarScreen';
import FloatingActionButtonAndPopover from './FloatingActionButtonAndPopover';
-import FreezeWrapper from '../../../../libs/Navigation/FreezeWrapper';
-import useWindowDimensions from '../../../../hooks/useWindowDimensions';
function SidebarScreen(props) {
const {isSmallScreenWidth} = useWindowDimensions();
diff --git a/src/pages/home/sidebar/SignInButton.js b/src/pages/home/sidebar/SignInButton.js
index 24b90d778445..9e8722e2e083 100644
--- a/src/pages/home/sidebar/SignInButton.js
+++ b/src/pages/home/sidebar/SignInButton.js
@@ -1,12 +1,12 @@
/* eslint-disable rulesdir/onyx-props-must-have-default */
import React from 'react';
import {View} from 'react-native';
-import PressableWithoutFeedback from '../../../components/Pressable/PressableWithoutFeedback';
-import Button from '../../../components/Button';
-import styles from '../../../styles/styles';
-import * as Session from '../../../libs/actions/Session';
-import useLocalize from '../../../hooks/useLocalize';
-import CONST from '../../../CONST';
+import Button from '@components/Button';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
function SignInButton() {
const {translate} = useLocalize();
diff --git a/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js b/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js
index 2599ac6b6942..8e41e1c6af6a 100644
--- a/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js
+++ b/src/pages/home/sidebar/SignInOrAvatarWithOptionalStatus.js
@@ -1,17 +1,17 @@
/* eslint-disable rulesdir/onyx-props-must-have-default */
-import React from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import withCurrentUserPersonalDetails from '../../../components/withCurrentUserPersonalDetails';
-import personalDetailsPropType from '../../personalDetailsPropType';
-import PressableAvatarWithIndicator from './PressableAvatarWithIndicator';
+import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import compose from '@libs/compose';
+import Permissions from '@libs/Permissions';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
import AvatarWithOptionalStatus from './AvatarWithOptionalStatus';
+import PressableAvatarWithIndicator from './PressableAvatarWithIndicator';
import SignInButton from './SignInButton';
-import * as Session from '../../../libs/actions/Session';
-import Permissions from '../../../libs/Permissions';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
const propTypes = {
/** The personal details of the person who is logged in */
diff --git a/src/pages/home/sidebar/SubNavigation/SubNavigation.js b/src/pages/home/sidebar/SubNavigation/SubNavigation.js
index 0c893b356099..ceb1d40dca50 100644
--- a/src/pages/home/sidebar/SubNavigation/SubNavigation.js
+++ b/src/pages/home/sidebar/SubNavigation/SubNavigation.js
@@ -1,12 +1,12 @@
-import React, {useEffect} from 'react';
import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
import {View} from 'react-native';
-import styles from '../../../../styles/styles';
-import SidebarLinksData from '../SidebarLinksData';
-import Timing from '../../../../libs/actions/Timing';
-import CONST from '../../../../CONST';
-import Performance from '../../../../libs/Performance';
-import safeAreaInsetPropTypes from '../../../safeAreaInsetPropTypes';
+import Performance from '@libs/Performance';
+import SidebarLinksData from '@pages/home/sidebar/SidebarLinksData';
+import safeAreaInsetPropTypes from '@pages/safeAreaInsetPropTypes';
+import styles from '@styles/styles';
+import Timing from '@userActions/Timing';
+import CONST from '@src/CONST';
const propTypes = {
/** Function called when a pinned chat is selected. */
diff --git a/src/pages/iou/IOUCurrencySelection.js b/src/pages/iou/IOUCurrencySelection.js
index 1f52f85e83a3..c7b5885865df 100644
--- a/src/pages/iou/IOUCurrencySelection.js
+++ b/src/pages/iou/IOUCurrencySelection.js
@@ -1,24 +1,24 @@
-import React, {useState, useMemo, useCallback, useRef, useEffect} from 'react';
-import {Keyboard} from 'react-native';
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {Keyboard} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import Navigation from '../../libs/Navigation/Navigation';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import compose from '../../libs/compose';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import {withNetwork} from '../../components/OnyxProvider';
-import * as CurrencyUtils from '../../libs/CurrencyUtils';
-import * as ReportActionsUtils from '../../libs/ReportActionsUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import ROUTES from '../../ROUTES';
-import {iouPropTypes, iouDefaultProps} from './propTypes';
-import SelectionList from '../../components/SelectionList';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import {withNetwork} from '@components/OnyxProvider';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportActionsUtils from '@libs/ReportActionsUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {iouDefaultProps, iouPropTypes} from './propTypes';
/**
* IOU Currency selection for selecting currency
@@ -154,7 +154,7 @@ function IOUCurrencySelection(props) {
testID={IOUCurrencySelection.displayName}
>
Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID))}
/>
{
// Get navigation to get initial isFocused value (only needed once during init!)
const navigation = useNavigation();
- const [isCameraActive, setIsCameraActive] = useState(navigation.isFocused());
+ const [isCameraActive, setIsCameraActive] = useState(() => navigation.isFocused());
// Retrieve the animation value from the tab navigator, which ranges from 0 to the total number of pages displayed.
// Even a minimal scroll towards the camera page (e.g., a value of 0.001 at start) should activate the camera for immediate responsiveness.
diff --git a/src/pages/iou/ReceiptSelector/index.js b/src/pages/iou/ReceiptSelector/index.js
index ca9fe90575e7..672b1458bf8e 100644
--- a/src/pages/iou/ReceiptSelector/index.js
+++ b/src/pages/iou/ReceiptSelector/index.js
@@ -1,34 +1,34 @@
-import {View, Text, PixelRatio, ActivityIndicator, PanResponder} from 'react-native';
-import React, {useCallback, useContext, useReducer, useRef, useState} from 'react';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
import PropTypes from 'prop-types';
+import React, {useCallback, useContext, useReducer, useRef, useState} from 'react';
+import {ActivityIndicator, PanResponder, PixelRatio, Text, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import * as IOU from '../../../libs/actions/IOU';
-import reportPropTypes from '../../reportPropTypes';
-import CONST from '../../../CONST';
-import ReceiptUpload from '../../../../assets/images/receipt-upload.svg';
-import Button from '../../../components/Button';
-import styles from '../../../styles/styles';
-import CopyTextToClipboard from '../../../components/CopyTextToClipboard';
-import ReceiptDropUI from '../ReceiptDropUI';
-import AttachmentPicker from '../../../components/AttachmentPicker';
-import ConfirmModal from '../../../components/ConfirmModal';
-import ONYXKEYS from '../../../ONYXKEYS';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
-import useLocalize from '../../../hooks/useLocalize';
-import {DragAndDropContext} from '../../../components/DragAndDrop/Provider';
-import {iouPropTypes, iouDefaultProps} from '../propTypes';
-import * as FileUtils from '../../../libs/fileDownload/FileUtils';
-import Navigation from '../../../libs/Navigation/Navigation';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import Icon from '../../../components/Icon';
-import themeColors from '../../../styles/themes/default';
-import Shutter from '../../../../assets/images/shutter.svg';
+import _ from 'underscore';
+import Hand from '@assets/images/hand.svg';
+import ReceiptUpload from '@assets/images/receipt-upload.svg';
+import Shutter from '@assets/images/shutter.svg';
+import AttachmentPicker from '@components/AttachmentPicker';
+import Button from '@components/Button';
+import ConfirmModal from '@components/ConfirmModal';
+import CopyTextToClipboard from '@components/CopyTextToClipboard';
+import {DragAndDropContext} from '@components/DragAndDrop/Provider';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes';
+import ReceiptDropUI from '@pages/iou/ReceiptDropUI';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import NavigationAwareCamera from './NavigationAwareCamera';
-import * as Browser from '../../../libs/Browser';
-import Hand from '../../../../assets/images/hand.svg';
-import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback';
const propTypes = {
/** The report on which the request is initiated on */
diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js
index 649b6ea521f3..d47a2c7739a2 100644
--- a/src/pages/iou/ReceiptSelector/index.native.js
+++ b/src/pages/iou/ReceiptSelector/index.native.js
@@ -1,30 +1,30 @@
-import {ActivityIndicator, Alert, AppState, Text, View} from 'react-native';
-import React, {useCallback, useEffect, useRef, useState} from 'react';
-import {useCameraDevices} from 'react-native-vision-camera';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
+import {ActivityIndicator, Alert, AppState, Text, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import {RESULTS} from 'react-native-permissions';
-import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback';
-import Icon from '../../../components/Icon';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import AttachmentPicker from '../../../components/AttachmentPicker';
-import styles from '../../../styles/styles';
-import Shutter from '../../../../assets/images/shutter.svg';
-import Hand from '../../../../assets/images/hand.svg';
-import * as IOU from '../../../libs/actions/IOU';
-import themeColors from '../../../styles/themes/default';
-import reportPropTypes from '../../reportPropTypes';
-import CONST from '../../../CONST';
-import Button from '../../../components/Button';
-import useLocalize from '../../../hooks/useLocalize';
-import ONYXKEYS from '../../../ONYXKEYS';
-import Log from '../../../libs/Log';
+import {useCameraDevices} from 'react-native-vision-camera';
+import Hand from '@assets/images/hand.svg';
+import Shutter from '@assets/images/shutter.svg';
+import AttachmentPicker from '@components/AttachmentPicker';
+import Button from '@components/Button';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import useLocalize from '@hooks/useLocalize';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import * as CameraPermission from './CameraPermission';
-import {iouPropTypes, iouDefaultProps} from '../propTypes';
import NavigationAwareCamera from './NavigationAwareCamera';
-import Navigation from '../../../libs/Navigation/Navigation';
-import * as FileUtils from '../../../libs/fileDownload/FileUtils';
const propTypes = {
/** React Navigation route */
diff --git a/src/pages/iou/SplitBillDetailsPage.js b/src/pages/iou/SplitBillDetailsPage.js
index 1c48a4f1a44a..1834907c78ea 100644
--- a/src/pages/iou/SplitBillDetailsPage.js
+++ b/src/pages/iou/SplitBillDetailsPage.js
@@ -1,28 +1,28 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
-import _ from 'underscore';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import personalDetailsPropType from '../personalDetailsPropType';
-import compose from '../../libs/compose';
-import reportActionPropTypes from '../home/report/reportActionPropTypes';
-import reportPropTypes from '../reportPropTypes';
-import transactionPropTypes from '../../components/transactionPropTypes';
-import withReportAndReportActionOrNotFound from '../home/report/withReportAndReportActionOrNotFound';
-import * as TransactionUtils from '../../libs/TransactionUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as IOU from '../../libs/actions/IOU';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import MoneyRequestConfirmationList from '../../components/MoneyRequestConfirmationList';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import MoneyRequestHeaderStatusBar from '../../components/MoneyRequestHeaderStatusBar';
-import useLocalize from '../../hooks/useLocalize';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MoneyRequestConfirmationList from '@components/MoneyRequestConfirmationList';
+import MoneyRequestHeaderStatusBar from '@components/MoneyRequestHeaderStatusBar';
+import ScreenWrapper from '@components/ScreenWrapper';
+import transactionPropTypes from '@components/transactionPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as TransactionUtils from '@libs/TransactionUtils';
+import reportActionPropTypes from '@pages/home/report/reportActionPropTypes';
+import withReportAndReportActionOrNotFound from '@pages/home/report/withReportAndReportActionOrNotFound';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/iou/WaypointEditor.js b/src/pages/iou/WaypointEditor.js
index a123976b326e..944f7e879cb6 100644
--- a/src/pages/iou/WaypointEditor.js
+++ b/src/pages/iou/WaypointEditor.js
@@ -1,29 +1,29 @@
-import React, {useMemo, useRef, useState} from 'react';
-import _ from 'underscore';
+import {useNavigation} from '@react-navigation/native';
import lodashGet from 'lodash/get';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useMemo, useRef, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import {useNavigation} from '@react-navigation/native';
-import AddressSearch from '../../components/AddressSearch';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import ONYXKEYS from '../../ONYXKEYS';
-import Form from '../../components/Form';
-import styles from '../../styles/styles';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import useLocalize from '../../hooks/useLocalize';
-import useNetwork from '../../hooks/useNetwork';
-import CONST from '../../CONST';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import ConfirmModal from '../../components/ConfirmModal';
-import * as Transaction from '../../libs/actions/Transaction';
-import * as ValidationUtils from '../../libs/ValidationUtils';
-import ROUTES from '../../ROUTES';
-import transactionPropTypes from '../../components/transactionPropTypes';
-import * as ErrorUtils from '../../libs/ErrorUtils';
+import _ from 'underscore';
+import AddressSearch from '@components/AddressSearch';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import ConfirmModal from '@components/ConfirmModal';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import ScreenWrapper from '@components/ScreenWrapper';
+import transactionPropTypes from '@components/transactionPropTypes';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as Transaction from '@userActions/Transaction';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Route params */
@@ -45,6 +45,9 @@ const propTypes = {
recentWaypoints: PropTypes.arrayOf(
PropTypes.shape({
+ /** The name of the location */
+ name: PropTypes.string,
+
/** A description of the location (usually the address) */
description: PropTypes.string,
@@ -163,6 +166,7 @@ function WaypointEditor({route: {params: {iouType = '', transactionID = '', wayp
lat: values.lat,
lng: values.lng,
address: values.address,
+ name: values.name,
};
Transaction.saveWaypoint(transactionID, waypointIndex, waypoint, isEditingWaypoint);
@@ -264,6 +268,7 @@ export default withOnyx({
// that the google autocomplete component expects for it's "predefined places" feature.
selector: (waypoints) =>
_.map(waypoints ? waypoints.slice(0, 5) : [], (waypoint) => ({
+ name: waypoint.name,
description: waypoint.address,
geometry: {
location: {
diff --git a/src/pages/iou/propTypes/index.js b/src/pages/iou/propTypes/index.js
index d41b4cbf1724..a03ed65dda9c 100644
--- a/src/pages/iou/propTypes/index.js
+++ b/src/pages/iou/propTypes/index.js
@@ -1,6 +1,6 @@
import PropTypes from 'prop-types';
-import CONST from '../../../CONST';
-import participantPropTypes from '../../../components/participantPropTypes';
+import participantPropTypes from '@components/participantPropTypes';
+import CONST from '@src/CONST';
const iouPropTypes = PropTypes.shape({
/** ID (iouType + reportID) of the request */
diff --git a/src/pages/iou/steps/MoneyRequestAmountForm.js b/src/pages/iou/steps/MoneyRequestAmountForm.js
index d84c4d9e3cd0..1ee8c607710a 100644
--- a/src/pages/iou/steps/MoneyRequestAmountForm.js
+++ b/src/pages/iou/steps/MoneyRequestAmountForm.js
@@ -1,22 +1,22 @@
-import React, {useEffect, useState, useCallback, useRef} from 'react';
-import {ScrollView, View} from 'react-native';
-import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
+import {ScrollView, View} from 'react-native';
import _ from 'underscore';
-import styles from '../../../styles/styles';
-import BigNumberPad from '../../../components/BigNumberPad';
-import * as CurrencyUtils from '../../../libs/CurrencyUtils';
-import * as MoneyRequestUtils from '../../../libs/MoneyRequestUtils';
-import Button from '../../../components/Button';
-import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
-import TextInputWithCurrencySymbol from '../../../components/TextInputWithCurrencySymbol';
-import useLocalize from '../../../hooks/useLocalize';
-import CONST from '../../../CONST';
-import FormHelpMessage from '../../../components/FormHelpMessage';
-import refPropTypes from '../../../components/refPropTypes';
-import getOperatingSystem from '../../../libs/getOperatingSystem';
-import * as Browser from '../../../libs/Browser';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
+import BigNumberPad from '@components/BigNumberPad';
+import Button from '@components/Button';
+import FormHelpMessage from '@components/FormHelpMessage';
+import refPropTypes from '@components/refPropTypes';
+import TextInputWithCurrencySymbol from '@components/TextInputWithCurrencySymbol';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as Browser from '@libs/Browser';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import getOperatingSystem from '@libs/getOperatingSystem';
+import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const propTypes = {
/** IOU amount saved in Onyx */
@@ -136,10 +136,17 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
if (!_.isEmpty(formError)) {
setFormError('');
}
+
+ // setCurrentAmount contains another setState(setSelection) making it error-prone since it is leading to setSelection being called twice for a single setCurrentAmount call. This solution introducing the hasSelectionBeenSet flag was chosen for its simplicity and lower risk of future errors https://github.com/Expensify/App/issues/23300#issuecomment-1766314724.
+
+ let hasSelectionBeenSet = false;
setCurrentAmount((prevAmount) => {
const strippedAmount = MoneyRequestUtils.stripCommaFromAmount(newAmountWithoutSpaces);
const isForwardDelete = prevAmount.length > strippedAmount.length && forwardDeletePressedRef.current;
- setSelection((prevSelection) => getNewSelection(prevSelection, isForwardDelete ? strippedAmount.length : prevAmount.length, strippedAmount.length));
+ if (!hasSelectionBeenSet) {
+ hasSelectionBeenSet = true;
+ setSelection((prevSelection) => getNewSelection(prevSelection, isForwardDelete ? strippedAmount.length : prevAmount.length, strippedAmount.length));
+ }
return strippedAmount;
});
},
@@ -261,14 +268,14 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
}}
onKeyPress={textInputKeyPress}
/>
+ {!_.isEmpty(formError) && (
+
+ )}
- {!_.isEmpty(formError) && (
-
- )}
onMouseDown(event, [NUM_PAD_CONTAINER_VIEW_ID, NUM_PAD_VIEW_ID])}
style={[styles.w100, styles.justifyContentEnd, styles.pageWrapper, styles.pt0]}
@@ -283,10 +290,11 @@ function MoneyRequestAmountForm({amount, currency, isEditing, forwardedRef, onCu
) : null}
@@ -299,10 +307,14 @@ MoneyRequestAmountForm.propTypes = propTypes;
MoneyRequestAmountForm.defaultProps = defaultProps;
MoneyRequestAmountForm.displayName = 'MoneyRequestAmountForm';
-export default React.forwardRef((props, ref) => (
+const MoneyRequestAmountFormWithRef = React.forwardRef((props, ref) => (
));
+
+MoneyRequestAmountFormWithRef.displayName = 'MoneyRequestAmountFormWithRef';
+
+export default MoneyRequestAmountFormWithRef;
diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js
index 8b697cde4880..79cf48ce634d 100644
--- a/src/pages/iou/steps/MoneyRequestConfirmPage.js
+++ b/src/pages/iou/steps/MoneyRequestConfirmPage.js
@@ -1,32 +1,33 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import MoneyRequestConfirmationList from '../../../components/MoneyRequestConfirmationList';
-import CONST from '../../../CONST';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import styles from '../../../styles/styles';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import * as IOU from '../../../libs/actions/IOU';
-import compose from '../../../libs/compose';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import * as OptionsListUtils from '../../../libs/OptionsListUtils';
-import * as MoneyRequestUtils from '../../../libs/MoneyRequestUtils';
-import withLocalize from '../../../components/withLocalize';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ONYXKEYS from '../../../ONYXKEYS';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../../components/withCurrentUserPersonalDetails';
-import reportPropTypes from '../../reportPropTypes';
-import personalDetailsPropType from '../../personalDetailsPropType';
-import * as FileUtils from '../../../libs/fileDownload/FileUtils';
-import * as Policy from '../../../libs/actions/Policy';
-import useNetwork from '../../../hooks/useNetwork';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
-import {iouPropTypes, iouDefaultProps} from '../propTypes';
-import * as Expensicons from '../../../components/Icon/Expensicons';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MoneyRequestConfirmationList from '@components/MoneyRequestConfirmationList';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize from '@components/withLocalize';
+import useInitialValue from '@hooks/useInitialValue';
+import useNetwork from '@hooks/useNetwork';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import compose from '@libs/compose';
+import * as FileUtils from '@libs/fileDownload/FileUtils';
+import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as IOU from '@userActions/IOU';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** React Navigation route */
@@ -63,10 +64,10 @@ function MoneyRequestConfirmPage(props) {
const {isOffline} = useNetwork();
const {windowWidth} = useWindowDimensions();
const prevMoneyRequestId = useRef(props.iou.id);
- const iouType = useRef(lodashGet(props.route, 'params.iouType', ''));
- const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType.current, props.selectedTab);
+ const iouType = useInitialValue(() => lodashGet(props.route, 'params.iouType', ''));
+ const reportID = useInitialValue(() => lodashGet(props.route, 'params.reportID', ''));
+ const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType, props.selectedTab);
const isScanRequest = MoneyRequestUtils.isScanRequest(props.selectedTab);
- const reportID = useRef(lodashGet(props.route, 'params.reportID', ''));
const [receiptFile, setReceiptFile] = useState();
const participants = useMemo(
() =>
@@ -77,7 +78,7 @@ function MoneyRequestConfirmPage(props) {
[props.iou.participants, props.personalDetails],
);
const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(props.report)), [props.report]);
- const isManualRequestDM = props.selectedTab === CONST.TAB.MANUAL && iouType.current === CONST.IOU.TYPE.REQUEST;
+ const isManualRequestDM = props.selectedTab === CONST.TAB.MANUAL && iouType === CONST.IOU.TYPE.REQUEST;
useEffect(() => {
IOU.resetMoneyRequestCategory();
@@ -101,47 +102,47 @@ function MoneyRequestConfirmPage(props) {
}
FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename).then((file) => {
if (!file) {
- Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType.current, reportID.current));
+ Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID));
} else {
const receipt = file;
receipt.state = file && isManualRequestDM ? CONST.IOU.RECEIPT_STATE.OPEN : CONST.IOU.RECEIPT_STATE.SCANREADY;
setReceiptFile(receipt);
}
});
- }, [props.iou.receiptPath, props.iou.receiptFilename, isManualRequestDM]);
+ }, [props.iou.receiptPath, props.iou.receiptFilename, isManualRequestDM, iouType, reportID]);
useEffect(() => {
// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
if (!isDistanceRequest && prevMoneyRequestId.current !== props.iou.id) {
// The ID is cleared on completing a request. In that case, we will do nothing.
if (props.iou.id) {
- Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType.current, reportID.current), true);
+ Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true);
}
return;
}
// Reset the money request Onyx if the ID in Onyx does not match the ID from params
- const moneyRequestId = `${iouType.current}${reportID.current}`;
+ const moneyRequestId = `${iouType}${reportID}`;
const shouldReset = !isDistanceRequest && props.iou.id !== moneyRequestId;
if (shouldReset) {
IOU.resetMoneyRequestInfo(moneyRequestId);
}
if (_.isEmpty(props.iou.participants) || (props.iou.amount === 0 && !props.iou.receiptPath && !isDistanceRequest) || shouldReset || ReportUtils.isArchivedRoom(props.report)) {
- Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType.current, reportID.current), true);
+ Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), true);
}
return () => {
prevMoneyRequestId.current = props.iou.id;
};
- }, [props.iou.participants, props.iou.amount, props.iou.id, props.iou.receiptPath, isDistanceRequest, props.report]);
+ }, [props.iou.participants, props.iou.amount, props.iou.id, props.iou.receiptPath, isDistanceRequest, props.report, iouType, reportID]);
const navigateBack = () => {
let fallback;
- if (reportID.current) {
- fallback = ROUTES.MONEY_REQUEST.getRoute(iouType.current, reportID.current);
+ if (reportID) {
+ fallback = ROUTES.MONEY_REQUEST.getRoute(iouType, reportID);
} else {
- fallback = ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType.current);
+ fallback = ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType);
}
Navigation.goBack(fallback);
};
@@ -211,8 +212,8 @@ function MoneyRequestConfirmPage(props) {
const trimmedComment = props.iou.comment.trim();
// If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed
- if (iouType.current === CONST.IOU.TYPE.SPLIT && props.iou.receiptPath) {
- const existingSplitChatReportID = CONST.REGEX.NUMBER.test(reportID.current) ? reportID.current : '';
+ if (iouType === CONST.IOU.TYPE.SPLIT && props.iou.receiptPath) {
+ const existingSplitChatReportID = CONST.REGEX.NUMBER.test(reportID) ? reportID : '';
FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename).then((receipt) => {
IOU.startSplitBill(
selectedParticipants,
@@ -228,7 +229,7 @@ function MoneyRequestConfirmPage(props) {
// IOUs created from a group report will have a reportID param in the route.
// Since the user is already viewing the report, we don't need to navigate them to the report
- if (iouType.current === CONST.IOU.TYPE.SPLIT && CONST.REGEX.NUMBER.test(reportID.current)) {
+ if (iouType === CONST.IOU.TYPE.SPLIT && CONST.REGEX.NUMBER.test(reportID)) {
IOU.splitBill(
selectedParticipants,
props.currentUserPersonalDetails.login,
@@ -237,13 +238,13 @@ function MoneyRequestConfirmPage(props) {
trimmedComment,
props.iou.currency,
props.iou.category,
- reportID.current,
+ reportID,
);
return;
}
// If the request is created from the global create menu, we also navigate the user to the group report
- if (iouType.current === CONST.IOU.TYPE.SPLIT) {
+ if (iouType === CONST.IOU.TYPE.SPLIT) {
IOU.splitBillAndOpenReport(
selectedParticipants,
props.currentUserPersonalDetails.login,
@@ -281,6 +282,8 @@ function MoneyRequestConfirmPage(props) {
requestMoney,
createDistanceRequest,
receiptFile,
+ iouType,
+ reportID,
],
);
@@ -312,14 +315,18 @@ function MoneyRequestConfirmPage(props) {
return props.translate('common.distance');
}
- if (iouType.current === CONST.IOU.TYPE.SPLIT) {
+ if (iouType === CONST.IOU.TYPE.SPLIT) {
return props.translate('iou.split');
}
- if (iouType.current === CONST.IOU.TYPE.SEND) {
+ if (iouType === CONST.IOU.TYPE.SEND) {
return props.translate('common.send');
}
+ if (isScanRequest) {
+ return props.translate('tabSelector.scan');
+ }
+
return props.translate('tabSelector.manual');
};
@@ -339,13 +346,13 @@ function MoneyRequestConfirmPage(props) {
{
icon: Expensicons.Receipt,
text: props.translate('receipt.addReceipt'),
- onSelected: () => Navigation.navigate(ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType.current, reportID.current)),
+ onSelected: () => Navigation.navigate(ROUTES.MONEY_REQUEST_RECEIPT.getRoute(iouType, reportID)),
},
]}
/>
lodashGet(route, 'params.iouType', ''));
+ const reportID = useInitialValue(() => lodashGet(route, 'params.reportID', ''));
+ const isDistanceRequest = MoneyRequestUtils.isDistanceRequest(iouType, selectedTab);
+ const isSendRequest = iouType === CONST.IOU.TYPE.SEND;
const isScanRequest = MoneyRequestUtils.isScanRequest(selectedTab);
const isSplitRequest = iou.id === CONST.IOU.TYPE.SPLIT;
const [headerTitle, setHeaderTitle] = useState();
@@ -66,17 +66,23 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
return;
}
- setHeaderTitle(_.isEmpty(iou.participants) ? translate('tabSelector.manual') : translate('iou.split'));
- }, [iou.participants, isDistanceRequest, isSendRequest, translate]);
+ if (isScanRequest) {
+ setHeaderTitle(translate('tabSelector.scan'));
+ return;
+ }
+
+ setHeaderTitle(iou.isSplitRequest ? translate('iou.split') : translate('tabSelector.manual'));
+ }, [iou.isSplitRequest, isDistanceRequest, translate, isScanRequest, isSendRequest]);
const navigateToConfirmationStep = (moneyRequestType) => {
IOU.setMoneyRequestId(moneyRequestType);
- Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, reportID.current));
+ Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, reportID));
};
- const navigateBack = (forceFallback = false) => {
- Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType.current, reportID.current), forceFallback);
- };
+ const navigateBack = useCallback((forceFallback = false) => {
+ Navigation.goBack(ROUTES.MONEY_REQUEST.getRoute(iouType, reportID), forceFallback);
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- no deps as we use only initial values
+ }, []);
useEffect(() => {
// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
@@ -89,7 +95,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
}
// Reset the money request Onyx if the ID in Onyx does not match the ID from params
- const moneyRequestId = `${iouType.current}${reportID.current}`;
+ const moneyRequestId = `${iouType}${reportID}`;
const shouldReset = iou.id !== moneyRequestId;
if (shouldReset) {
IOU.resetMoneyRequestInfo(moneyRequestId);
@@ -101,7 +107,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
return () => {
prevMoneyRequestId.current = iou.id;
};
- }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest]);
+ }, [iou.amount, iou.id, iou.receiptPath, isDistanceRequest, isSplitRequest, iouType, reportID, navigateBack]);
return (
(optionsSelectorRef.current = el)}
- participants={iou.participants}
+ participants={iou.isSplitRequest ? iou.participants : []}
onAddParticipants={IOU.setMoneyRequestParticipants}
- navigateToRequest={() => navigateToConfirmationStep(iouType.current)}
+ navigateToRequest={() => navigateToConfirmationStep(iouType)}
navigateToSplit={() => navigateToConfirmationStep(CONST.IOU.TYPE.SPLIT)}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
- iouType={iouType.current}
+ iouType={iouType}
isDistanceRequest={isDistanceRequest}
isScanRequest={isScanRequest}
/>
diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
index 9f1e5a416995..5d47a51fb73c 100755
--- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
+++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
@@ -1,21 +1,21 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import styles from '../../../../styles/styles';
-import OptionsSelector from '../../../../components/OptionsSelector';
-import * as OptionsListUtils from '../../../../libs/OptionsListUtils';
-import * as ReportUtils from '../../../../libs/ReportUtils';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import * as Browser from '../../../../libs/Browser';
-import compose from '../../../../libs/compose';
-import CONST from '../../../../CONST';
-import personalDetailsPropType from '../../../personalDetailsPropType';
-import reportPropTypes from '../../../reportPropTypes';
-import refPropTypes from '../../../../components/refPropTypes';
+import OptionsSelector from '@components/OptionsSelector';
+import refPropTypes from '@components/refPropTypes';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Beta features list */
@@ -157,9 +157,10 @@ function MoneyRequestParticipantsSelector({
* @param {Object} option
*/
const addSingleParticipant = (option) => {
- onAddParticipants([
- {accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true, searchText: option.searchText},
- ]);
+ onAddParticipants(
+ [{accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true, searchText: option.searchText}],
+ false,
+ );
navigateToRequest();
};
@@ -198,8 +199,7 @@ function MoneyRequestParticipantsSelector({
},
];
}
-
- onAddParticipants(newSelectedOptions);
+ onAddParticipants(newSelectedOptions, newSelectedOptions.length !== 0);
},
[participants, onAddParticipants],
);
@@ -283,6 +283,16 @@ MoneyRequestParticipantsSelector.propTypes = propTypes;
MoneyRequestParticipantsSelector.defaultProps = defaultProps;
MoneyRequestParticipantsSelector.displayName = 'MoneyRequestParticipantsSelector';
+const MoneyRequestParticipantsSelectorWithRef = React.forwardRef((props, ref) => (
+
+));
+
+MoneyRequestParticipantsSelectorWithRef.displayName = 'MoneyRequestParticipantsSelectorWithRef';
+
export default compose(
withLocalize,
withOnyx({
@@ -296,12 +306,4 @@ export default compose(
key: ONYXKEYS.BETAS,
},
}),
-)(
- React.forwardRef((props, ref) => (
-
- )),
-);
+)(MoneyRequestParticipantsSelectorWithRef);
diff --git a/src/pages/iou/steps/NewRequestAmountPage.js b/src/pages/iou/steps/NewRequestAmountPage.js
index 15a2c74d8a95..e531e6706f55 100644
--- a/src/pages/iou/steps/NewRequestAmountPage.js
+++ b/src/pages/iou/steps/NewRequestAmountPage.js
@@ -1,26 +1,26 @@
+import {useFocusEffect} from '@react-navigation/native';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useRef} from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import {useFocusEffect} from '@react-navigation/native';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import ONYXKEYS from '../../../ONYXKEYS';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import * as CurrencyUtils from '../../../libs/CurrencyUtils';
-import reportPropTypes from '../../reportPropTypes';
-import * as IOU from '../../../libs/actions/IOU';
-import useLocalize from '../../../hooks/useLocalize';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import * as IOUUtils from '@libs/IOUUtils';
+import * as MoneyRequestUtils from '@libs/MoneyRequestUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import {iouDefaultProps, iouPropTypes} from '@pages/iou/propTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as IOU from '@userActions/IOU';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import MoneyRequestAmountForm from './MoneyRequestAmountForm';
-import * as IOUUtils from '../../../libs/IOUUtils';
-import * as MoneyRequestUtils from '../../../libs/MoneyRequestUtils';
-import FullPageNotFoundView from '../../../components/BlockingViews/FullPageNotFoundView';
-import styles from '../../../styles/styles';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import {iouPropTypes, iouDefaultProps} from '../propTypes';
-import CONST from '../../../CONST';
const propTypes = {
/** React Navigation route */
diff --git a/src/pages/reportMetadataPropTypes.js b/src/pages/reportMetadataPropTypes.js
index a75d71aef7b3..65ed01952977 100644
--- a/src/pages/reportMetadataPropTypes.js
+++ b/src/pages/reportMetadataPropTypes.js
@@ -1,9 +1,12 @@
import PropTypes from 'prop-types';
export default PropTypes.shape({
- /** Are we loading more report actions? */
- isLoadingMoreReportActions: PropTypes.bool,
+ /** Are we loading newer report actions? */
+ isLoadingNewerReportActions: PropTypes.bool,
+
+ /** Are we loading older report actions? */
+ isLoadingOlderReportActions: PropTypes.bool,
/** Flag to check if the report actions data are loading */
- isLoadingReportActions: PropTypes.bool,
+ isLoadingInitialReportActions: PropTypes.bool,
});
diff --git a/src/pages/reportPropTypes.js b/src/pages/reportPropTypes.js
index b70438171a73..a3bbbda5c0bf 100644
--- a/src/pages/reportPropTypes.js
+++ b/src/pages/reportPropTypes.js
@@ -1,7 +1,7 @@
-import _ from 'underscore';
import PropTypes from 'prop-types';
-import CONST from '../CONST';
-import avatarPropTypes from '../components/avatarPropTypes';
+import _ from 'underscore';
+import avatarPropTypes from '@components/avatarPropTypes';
+import CONST from '@src/CONST';
export default PropTypes.shape({
/** The specific type of chat */
diff --git a/src/pages/settings/AboutPage/AboutPage.js b/src/pages/settings/AboutPage/AboutPage.js
index 25b6197f87f8..8e9618036861 100644
--- a/src/pages/settings/AboutPage/AboutPage.js
+++ b/src/pages/settings/AboutPage/AboutPage.js
@@ -1,27 +1,28 @@
-import _ from 'underscore';
-import React from 'react';
+import React, {useMemo, useRef} from 'react';
import {ScrollView, View} from 'react-native';
import DeviceInfo from 'react-native-device-info';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import styles from '../../../styles/styles';
-import Text from '../../../components/Text';
-import TextLink from '../../../components/TextLink';
-import CONST from '../../../CONST';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import MenuItem from '../../../components/MenuItem';
-import Logo from '../../../../assets/images/new-expensify.svg';
+import _ from 'underscore';
+import Logo from '@assets/images/new-expensify.svg';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItemList from '@components/MenuItemList';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useWaitForNavigation from '@hooks/useWaitForNavigation';
+import compose from '@libs/compose';
+import * as Environment from '@libs/Environment/Environment';
+import Navigation from '@libs/Navigation/Navigation';
+import {CONTEXT_MENU_TYPES} from '@pages/home/report/ContextMenu/ContextMenuActions';
+import * as ReportActionContextMenu from '@pages/home/report/ContextMenu/ReportActionContextMenu';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
import pkg from '../../../../package.json';
-import * as Report from '../../../libs/actions/Report';
-import * as Link from '../../../libs/actions/Link';
-import compose from '../../../libs/compose';
-import * as ReportActionContextMenu from '../../home/report/ContextMenu/ReportActionContextMenu';
-import {CONTEXT_MENU_TYPES} from '../../home/report/ContextMenu/ContextMenuActions';
-import * as Environment from '../../../libs/Environment/Environment';
const propTypes = {
...withLocalizePropTypes,
@@ -40,46 +41,57 @@ function getFlavor() {
}
function AboutPage(props) {
- let popoverAnchor;
- const menuItems = [
- {
- translationKey: 'initialSettingsPage.aboutPage.appDownloadLinks',
- icon: Expensicons.Link,
- action: () => {
- Navigation.navigate(ROUTES.SETTINGS_APP_DOWNLOAD_LINKS);
+ const {translate} = props;
+ const popoverAnchor = useRef(null);
+ const waitForNavigate = useWaitForNavigation();
+
+ const menuItems = useMemo(() => {
+ const baseMenuItems = [
+ {
+ translationKey: 'initialSettingsPage.aboutPage.appDownloadLinks',
+ icon: Expensicons.Link,
+ action: waitForNavigate(() => Navigation.navigate(ROUTES.SETTINGS_APP_DOWNLOAD_LINKS)),
+ },
+ {
+ translationKey: 'initialSettingsPage.aboutPage.viewKeyboardShortcuts',
+ icon: Expensicons.Keyboard,
+ action: waitForNavigate(() => Navigation.navigate(ROUTES.KEYBOARD_SHORTCUTS)),
},
- },
- {
- translationKey: 'initialSettingsPage.aboutPage.viewKeyboardShortcuts',
- icon: Expensicons.Keyboard,
- action: () => {
- Navigation.navigate(ROUTES.KEYBOARD_SHORTCUTS);
+ {
+ translationKey: 'initialSettingsPage.aboutPage.viewTheCode',
+ icon: Expensicons.Eye,
+ iconRight: Expensicons.NewWindow,
+ action: () => {
+ Link.openExternalLink(CONST.GITHUB_URL);
+ },
},
- },
- {
- translationKey: 'initialSettingsPage.aboutPage.viewTheCode',
- icon: Expensicons.Eye,
- iconRight: Expensicons.NewWindow,
- action: () => {
- Link.openExternalLink(CONST.GITHUB_URL);
+ {
+ translationKey: 'initialSettingsPage.aboutPage.viewOpenJobs',
+ icon: Expensicons.MoneyBag,
+ iconRight: Expensicons.NewWindow,
+ action: () => {
+ Link.openExternalLink(CONST.UPWORK_URL);
+ },
+ link: CONST.UPWORK_URL,
},
- link: CONST.GITHUB_URL,
- },
- {
- translationKey: 'initialSettingsPage.aboutPage.viewOpenJobs',
- icon: Expensicons.MoneyBag,
- iconRight: Expensicons.NewWindow,
- action: () => {
- Link.openExternalLink(CONST.UPWORK_URL);
+ {
+ translationKey: 'initialSettingsPage.aboutPage.reportABug',
+ icon: Expensicons.Bug,
+ action: waitForNavigate(Report.navigateToConciergeChat),
},
- link: CONST.UPWORK_URL,
- },
- {
- translationKey: 'initialSettingsPage.aboutPage.reportABug',
- icon: Expensicons.Bug,
- action: Report.navigateToConciergeChat,
- },
- ];
+ ];
+ return _.map(baseMenuItems, (item) => ({
+ key: item.translationKey,
+ title: translate(item.translationKey),
+ icon: item.icon,
+ iconRight: item.iconRight,
+ onPress: item.action,
+ shouldShowRightIcon: true,
+ onSecondaryInteraction: !_.isEmpty(item.link) ? (e) => ReportActionContextMenu.showContextMenu(CONTEXT_MENU_TYPES.LINK, e, item.link, popoverAnchor) : undefined,
+ ref: popoverAnchor,
+ shouldBlockSelection: Boolean(item.link),
+ }));
+ }, [translate, waitForNavigate]);
return (
{props.translate('initialSettingsPage.aboutPage.description')}
- {_.map(menuItems, (item) => (
- item.action()}
- shouldBlockSelection={Boolean(item.link)}
- onSecondaryInteraction={
- !_.isEmpty(item.link) ? (e) => ReportActionContextMenu.showContextMenu(CONTEXT_MENU_TYPES.LINK, e, item.link, popoverAnchor) : undefined
- }
- ref={(el) => (popoverAnchor = el)}
- shouldShowRightIcon
- />
- ))}
+
@@ -357,7 +358,8 @@ function InitialSettingsPage(props) {
diff --git a/src/pages/settings/Preferences/LanguagePage.js b/src/pages/settings/Preferences/LanguagePage.js
index f55e49eb561e..9ef95d599e97 100644
--- a/src/pages/settings/Preferences/LanguagePage.js
+++ b/src/pages/settings/Preferences/LanguagePage.js
@@ -1,14 +1,14 @@
-import _ from 'underscore';
-import React from 'react';
import PropTypes from 'prop-types';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as App from '../../../libs/actions/App';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import CONST from '../../../CONST';
-import SelectionList from '../../../components/SelectionList';
+import React from 'react';
+import _ from 'underscore';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as App from '@userActions/App';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Preferences/PreferencesPage.js b/src/pages/settings/Preferences/PreferencesPage.js
index 9e30e99ff38f..c86eed258151 100755
--- a/src/pages/settings/Preferences/PreferencesPage.js
+++ b/src/pages/settings/Preferences/PreferencesPage.js
@@ -1,24 +1,24 @@
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import ONYXKEYS from '../../../ONYXKEYS';
-import styles from '../../../styles/styles';
-import themeColors from '../../../styles/themes/default';
-import Text from '../../../components/Text';
-import CONST from '../../../CONST';
-import * as User from '../../../libs/actions/User';
-import Switch from '../../../components/Switch';
-import TestToolMenu from '../../../components/TestToolMenu';
-import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription';
-import IllustratedHeaderPageLayout from '../../../components/IllustratedHeaderPageLayout';
-import * as LottieAnimations from '../../../components/LottieAnimations';
-import SCREENS from '../../../SCREENS';
-import useEnvironment from '../../../hooks/useEnvironment';
-import useLocalize from '../../../hooks/useLocalize';
+import IllustratedHeaderPageLayout from '@components/IllustratedHeaderPageLayout';
+import * as LottieAnimations from '@components/LottieAnimations';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import Switch from '@components/Switch';
+import TestToolMenu from '@components/TestToolMenu';
+import Text from '@components/Text';
+import useEnvironment from '@hooks/useEnvironment';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
const propTypes = {
/** The chat priority mode */
diff --git a/src/pages/settings/Preferences/PriorityModePage.js b/src/pages/settings/Preferences/PriorityModePage.js
index 38f856825dcc..73c6932b6218 100644
--- a/src/pages/settings/Preferences/PriorityModePage.js
+++ b/src/pages/settings/Preferences/PriorityModePage.js
@@ -1,18 +1,18 @@
-import _, {compose} from 'underscore';
+import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import styles from '../../../styles/styles';
-import Text from '../../../components/Text';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as User from '../../../libs/actions/User';
-import CONST from '../../../CONST';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import SelectionList from '../../../components/SelectionList';
+import _, {compose} from 'underscore';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** The chat priority mode */
diff --git a/src/pages/settings/Preferences/ThemePage.js b/src/pages/settings/Preferences/ThemePage.js
index 0dd6115e74e8..7802faecce14 100644
--- a/src/pages/settings/Preferences/ThemePage.js
+++ b/src/pages/settings/Preferences/ThemePage.js
@@ -1,19 +1,19 @@
-import _ from 'underscore';
+import PropTypes from 'prop-types';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import SelectionList from '../../../components/SelectionList';
-import styles from '../../../styles/styles';
-import ONYXKEYS from '../../../ONYXKEYS';
-import CONST from '../../../CONST';
-import compose from '../../../libs/compose';
-import Text from '../../../components/Text';
-import * as User from '../../../libs/actions/User';
+import _ from 'underscore';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js
index 7e8baba5a9ce..c48191957999 100644
--- a/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js
+++ b/src/pages/settings/Profile/Contacts/ContactMethodDetailsPage.js
@@ -1,31 +1,31 @@
import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
-import React, {Component} from 'react';
-import {View, ScrollView, Keyboard} from 'react-native';
import PropTypes from 'prop-types';
+import React, {Component} from 'react';
+import {Keyboard, ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import compose from '../../../../libs/compose';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import MenuItem from '../../../../components/MenuItem';
-import styles from '../../../../styles/styles';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import Text from '../../../../components/Text';
-import OfflineWithFeedback from '../../../../components/OfflineWithFeedback';
-import DotIndicatorMessage from '../../../../components/DotIndicatorMessage';
-import ConfirmModal from '../../../../components/ConfirmModal';
-import * as User from '../../../../libs/actions/User';
-import * as ErrorUtils from '../../../../libs/ErrorUtils';
-import themeColors from '../../../../styles/themes/default';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import ConfirmModal from '@components/ConfirmModal';
+import DotIndicatorMessage from '@components/DotIndicatorMessage';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import ValidateCodeForm from './ValidateCodeForm';
-import ROUTES from '../../../../ROUTES';
-import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
-import FullPageNotFoundView from '../../../../components/BlockingViews/FullPageNotFoundView';
-import CONST from '../../../../CONST';
const propTypes = {
/* Onyx Props */
@@ -335,6 +335,7 @@ class ContactMethodDetailsPage extends Component {
ContactMethodDetailsPage.propTypes = propTypes;
ContactMethodDetailsPage.defaultProps = defaultProps;
+ContactMethodDetailsPage.displayName = 'ContactMethodDetailsPage';
export default compose(
withLocalize,
diff --git a/src/pages/settings/Profile/Contacts/ContactMethodsPage.js b/src/pages/settings/Profile/Contacts/ContactMethodsPage.js
index c710013f9a68..fbd7b4340cec 100644
--- a/src/pages/settings/Profile/Contacts/ContactMethodsPage.js
+++ b/src/pages/settings/Profile/Contacts/ContactMethodsPage.js
@@ -2,24 +2,24 @@ import Str from 'expensify-common/lib/str';
import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React from 'react';
-import {View, ScrollView} from 'react-native';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import Button from '../../../../components/Button';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import CONST from '../../../../CONST';
-import compose from '../../../../libs/compose';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import ROUTES from '../../../../ROUTES';
-import styles from '../../../../styles/styles';
-import MenuItem from '../../../../components/MenuItem';
-import Text from '../../../../components/Text';
-import CopyTextToClipboard from '../../../../components/CopyTextToClipboard';
-import OfflineWithFeedback from '../../../../components/OfflineWithFeedback';
-import FixedFooter from '../../../../components/FixedFooter';
+import Button from '@components/Button';
+import CopyTextToClipboard from '@components/CopyTextToClipboard';
+import FixedFooter from '@components/FixedFooter';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js
index 480c425a9094..9e40ef65dfd6 100644
--- a/src/pages/settings/Profile/Contacts/NewContactMethodPage.js
+++ b/src/pages/settings/Profile/Contacts/NewContactMethodPage.js
@@ -1,25 +1,26 @@
-import React, {useRef} from 'react';
+import Str from 'expensify-common/lib/str';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useRef} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import Str from 'expensify-common/lib/str';
-import compose from '../../../../libs/compose';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import Text from '../../../../components/Text';
-import TextInput from '../../../../components/TextInput';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import ROUTES from '../../../../ROUTES';
-import styles from '../../../../styles/styles';
-import * as User from '../../../../libs/actions/User';
-import * as LoginUtils from '../../../../libs/LoginUtils';
-import * as ErrorUtils from '../../../../libs/ErrorUtils';
-import Form from '../../../../components/Form';
-import CONST from '../../../../CONST';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import * as LoginUtils from '@libs/LoginUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
@@ -104,7 +105,7 @@ function NewContactMethodPage(props) {
title={props.translate('contacts.newContactMethod')}
onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_CONTACT_METHODS)}
/>
-
+
);
}
diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js
index 73231cd315ad..3cdbb815f66f 100644
--- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js
+++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js
@@ -1,28 +1,28 @@
-import React, {useCallback, useState, useEffect, useRef, useImperativeHandle} from 'react';
-import {View} from 'react-native';
+import {useFocusEffect} from '@react-navigation/native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import _ from 'underscore';
+import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import {useFocusEffect} from '@react-navigation/native';
-import MagicCodeInput from '../../../../../components/MagicCodeInput';
-import * as ErrorUtils from '../../../../../libs/ErrorUtils';
-import withLocalize, {withLocalizePropTypes} from '../../../../../components/withLocalize';
-import ONYXKEYS from '../../../../../ONYXKEYS';
-import compose from '../../../../../libs/compose';
-import styles from '../../../../../styles/styles';
-import OfflineWithFeedback from '../../../../../components/OfflineWithFeedback';
-import * as ValidationUtils from '../../../../../libs/ValidationUtils';
-import * as User from '../../../../../libs/actions/User';
-import Button from '../../../../../components/Button';
-import DotIndicatorMessage from '../../../../../components/DotIndicatorMessage';
-import * as Session from '../../../../../libs/actions/Session';
-import Text from '../../../../../components/Text';
-import {withNetwork} from '../../../../../components/OnyxProvider';
-import PressableWithFeedback from '../../../../../components/Pressable/PressableWithFeedback';
-import themeColors from '../../../../../styles/themes/default';
-import * as StyleUtils from '../../../../../styles/StyleUtils';
-import CONST from '../../../../../CONST';
+import _ from 'underscore';
+import Button from '@components/Button';
+import DotIndicatorMessage from '@components/DotIndicatorMessage';
+import MagicCodeInput from '@components/MagicCodeInput';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {withNetwork} from '@components/OnyxProvider';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import * as Session from '@userActions/Session';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js
index 0fa231aec6f1..5d7bb11f4537 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js
@@ -1,25 +1,25 @@
-import React, {useMemo, useCallback, useEffect} from 'react';
+import lodashGet from 'lodash/get';
+import React, {useCallback, useEffect, useMemo} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails';
-import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import HeaderPageLayout from '../../../../components/HeaderPageLayout';
-import * as Expensicons from '../../../../components/Icon/Expensicons';
-import withLocalize from '../../../../components/withLocalize';
-import Button from '../../../../components/Button';
-import Text from '../../../../components/Text';
-import MenuItem from '../../../../components/MenuItem';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import * as User from '../../../../libs/actions/User';
-import MobileBackgroundImage from '../../../../../assets/images/money-stack.svg';
-import themeColors from '../../../../styles/themes/default';
-import useLocalize from '../../../../hooks/useLocalize';
-import styles from '../../../../styles/styles';
-import compose from '../../../../libs/compose';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import ROUTES from '../../../../ROUTES';
-import SCREENS from '../../../../SCREENS';
+import MobileBackgroundImage from '@assets/images/money-stack.svg';
+import Button from '@components/Button';
+import HeaderPageLayout from '@components/HeaderPageLayout';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize from '@components/withLocalize';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as User from '@userActions/User';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
const propTypes = {
...withCurrentUserPersonalDetailsPropTypes,
diff --git a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js b/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
index 189ec3e5f2f3..1d26c0e6dec4 100644
--- a/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
+++ b/src/pages/settings/Profile/CustomStatus/StatusSetPage.js
@@ -1,22 +1,23 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
-import Form from '../../../../components/Form';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import ROUTES from '../../../../ROUTES';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import compose from '../../../../libs/compose';
-import styles from '../../../../styles/styles';
-import useLocalize from '../../../../hooks/useLocalize';
-import CONST from '../../../../CONST';
-import EmojiPickerButtonDropdown from '../../../../components/EmojiPicker/EmojiPickerButtonDropdown';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import * as User from '../../../../libs/actions/User';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '../../../../components/withCurrentUserPersonalDetails';
-import TextInput from '../../../../components/TextInput';
+import EmojiPickerButtonDropdown from '@components/EmojiPicker/EmojiPickerButtonDropdown';
+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 withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** The draft status of the user */
@@ -52,7 +53,7 @@ function StatusSetPage({draftStatus, currentUserPersonalDetails}) {
title={translate('statusPage.status')}
onBackButtonPress={() => Navigation.goBack(ROUTES.SETTINGS_STATUS)}
/>
-
+
);
}
diff --git a/src/pages/settings/Profile/DisplayNamePage.js b/src/pages/settings/Profile/DisplayNamePage.js
index 0fe7fa20ce0a..379b5f225310 100644
--- a/src/pages/settings/Profile/DisplayNamePage.js
+++ b/src/pages/settings/Profile/DisplayNamePage.js
@@ -1,26 +1,26 @@
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../../components/withCurrentUserPersonalDetails';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import ONYXKEYS from '../../../ONYXKEYS';
-import CONST from '../../../CONST';
-import * as ValidationUtils from '../../../libs/ValidationUtils';
-import TextInput from '../../../components/TextInput';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import * as PersonalDetails from '../../../libs/actions/PersonalDetails';
-import compose from '../../../libs/compose';
-import * as ErrorUtils from '../../../libs/ErrorUtils';
-import ROUTES from '../../../ROUTES';
-import Navigation from '../../../libs/Navigation/Navigation';
-import FormProvider from '../../../components/Form/FormProvider';
-import InputWrapper from '../../../components/Form/InputWrapper';
-import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Profile/LoungeAccessPage.js b/src/pages/settings/Profile/LoungeAccessPage.js
index 81d63592211b..9c5c43463944 100644
--- a/src/pages/settings/Profile/LoungeAccessPage.js
+++ b/src/pages/settings/Profile/LoungeAccessPage.js
@@ -1,27 +1,27 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import ONYXKEYS from '../../../ONYXKEYS';
-import userPropTypes from '../userPropTypes';
-import NotFoundPage from '../../ErrorPage/NotFoundPage';
-import useLocalize from '../../../hooks/useLocalize';
-import FeatureList from '../../../components/FeatureList';
-import IllustratedHeaderPageLayout from '../../../components/IllustratedHeaderPageLayout';
-import * as LottieAnimations from '../../../components/LottieAnimations';
-import compose from '../../../libs/compose';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../../components/withCurrentUserPersonalDetails';
-import LinearGradient from '../../../components/LinearGradient';
-import styles from '../../../styles/styles';
-import Avatar from '../../../components/Avatar';
-import Text from '../../../components/Text';
-import * as UserUtils from '../../../libs/UserUtils';
-import CONST from '../../../CONST';
-import themeColors from '../../../styles/themes/default';
-import * as LocalePhoneNumber from '../../../libs/LocalePhoneNumber';
+import Avatar from '@components/Avatar';
+import FeatureList from '@components/FeatureList';
+import * as Illustrations from '@components/Icon/Illustrations';
+import IllustratedHeaderPageLayout from '@components/IllustratedHeaderPageLayout';
+import LinearGradient from '@components/LinearGradient';
+import * as LottieAnimations from '@components/LottieAnimations';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import Navigation from '@libs/Navigation/Navigation';
+import * as UserUtils from '@libs/UserUtils';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import userPropTypes from '@pages/settings/userPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** The session of the logged in person */
diff --git a/src/pages/settings/Profile/PersonalDetails/AddressPage.js b/src/pages/settings/Profile/PersonalDetails/AddressPage.js
index 3a49b6901035..a6cb069780b2 100644
--- a/src/pages/settings/Profile/PersonalDetails/AddressPage.js
+++ b/src/pages/settings/Profile/PersonalDetails/AddressPage.js
@@ -1,27 +1,27 @@
+import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
-import React, {useState, useCallback, useEffect, useMemo} from 'react';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
-import {CONST as COMMON_CONST} from 'expensify-common/lib/CONST';
import {withOnyx} from 'react-native-onyx';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import Form from '../../../../components/Form';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import CONST from '../../../../CONST';
-import TextInput from '../../../../components/TextInput';
-import styles from '../../../../styles/styles';
-import * as PersonalDetails from '../../../../libs/actions/PersonalDetails';
-import * as ValidationUtils from '../../../../libs/ValidationUtils';
-import AddressSearch from '../../../../components/AddressSearch';
-import StatePicker from '../../../../components/StatePicker';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ROUTES from '../../../../ROUTES';
-import useLocalize from '../../../../hooks/useLocalize';
-import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
-import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
-import CountrySelector from '../../../../components/CountrySelector';
+import _ from 'underscore';
+import AddressSearch from '@components/AddressSearch';
+import CountrySelector from '@components/CountrySelector';
+import Form from '@components/Form';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import StatePicker from '@components/StatePicker';
+import TextInput from '@components/TextInput';
+import useLocalize from '@hooks/useLocalize';
+import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js
index 741974776df1..a0c2a02b2cb5 100644
--- a/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js
+++ b/src/pages/settings/Profile/PersonalDetails/CountrySelectionPage.js
@@ -1,15 +1,15 @@
-import React, {useState, useMemo, useCallback} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useMemo, useState} from 'react';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import SelectionList from '../../../../components/SelectionList';
-import searchCountryOptions from '../../../../libs/searchCountryOptions';
-import StringUtils from '../../../../libs/StringUtils';
-import CONST from '../../../../CONST';
-import useLocalize from '../../../../hooks/useLocalize';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import searchCountryOptions from '@libs/searchCountryOptions';
+import StringUtils from '@libs/StringUtils';
+import CONST from '@src/CONST';
const propTypes = {
/** Route from navigation */
diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js
index 68d81d64c604..51164fa29dac 100644
--- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js
+++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js
@@ -1,23 +1,23 @@
+import {subYears} from 'date-fns';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import {subYears} from 'date-fns';
-import CONST from '../../../../CONST';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import ROUTES from '../../../../ROUTES';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import NewDatePicker from '../../../../components/NewDatePicker';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import * as ValidationUtils from '../../../../libs/ValidationUtils';
-import * as PersonalDetails from '../../../../libs/actions/PersonalDetails';
-import compose from '../../../../libs/compose';
-import styles from '../../../../styles/styles';
-import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
-import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
-import FormProvider from '../../../../components/Form/FormProvider';
+import FormProvider from '@components/Form/FormProvider';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import NewDatePicker from '@components/NewDatePicker';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js
index 046af8204b97..eeb6d8217f9f 100644
--- a/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js
+++ b/src/pages/settings/Profile/PersonalDetails/LegalNamePage.js
@@ -1,25 +1,26 @@
-import _ from 'underscore';
-import React, {useCallback} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import Form from '../../../../components/Form';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import CONST from '../../../../CONST';
-import * as ValidationUtils from '../../../../libs/ValidationUtils';
-import TextInput from '../../../../components/TextInput';
-import styles from '../../../../styles/styles';
-import * as PersonalDetails from '../../../../libs/actions/PersonalDetails';
-import compose from '../../../../libs/compose';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import ROUTES from '../../../../ROUTES';
-import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
-import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
-import * as ErrorUtils from '../../../../libs/ErrorUtils';
+import _ from 'underscore';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
@@ -87,7 +88,7 @@ function LegalNamePage(props) {
{isLoadingPersonalDetails ? (
) : (
-
+
)}
);
diff --git a/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js b/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js
index 3b695de3fcb7..3a35f65f45ae 100644
--- a/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js
+++ b/src/pages/settings/Profile/PersonalDetails/PersonalDetailsInitialPage.js
@@ -1,22 +1,22 @@
-import React from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React from 'react';
import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../../../components/withLocalize';
-import ROUTES from '../../../../ROUTES';
-import Text from '../../../../components/Text';
-import styles from '../../../../styles/styles';
-import Navigation from '../../../../libs/Navigation/Navigation';
-import compose from '../../../../libs/compose';
-import MenuItemWithTopDescription from '../../../../components/MenuItemWithTopDescription';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import {withNetwork} from '../../../../components/OnyxProvider';
-import usePrivatePersonalDetails from '../../../../hooks/usePrivatePersonalDetails';
-import FullscreenLoadingIndicator from '../../../../components/FullscreenLoadingIndicator';
-import * as PersonalDetailsUtils from '../../../../libs/PersonalDetailsUtils';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import {withNetwork} from '@components/OnyxProvider';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import usePrivatePersonalDetails from '@hooks/usePrivatePersonalDetails';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import styles from '@styles/styles';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js
index dda3dd4f456a..7ec8e05b76ff 100755
--- a/src/pages/settings/Profile/ProfilePage.js
+++ b/src/pages/settings/Profile/ProfilePage.js
@@ -1,29 +1,29 @@
import lodashGet from 'lodash/get';
-import React, {useEffect} from 'react';
-import {View, ScrollView} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import AvatarWithImagePicker from '../../../components/AvatarWithImagePicker';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import MenuItem from '../../../components/MenuItem';
-import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../../components/withCurrentUserPersonalDetails';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import CONST from '../../../CONST';
-import * as PersonalDetails from '../../../libs/actions/PersonalDetails';
-import compose from '../../../libs/compose';
-import Navigation from '../../../libs/Navigation/Navigation';
-import * as UserUtils from '../../../libs/UserUtils';
-import ROUTES from '../../../ROUTES';
-import styles from '../../../styles/styles';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import ONYXKEYS from '../../../ONYXKEYS';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import userPropTypes from '../userPropTypes';
-import * as App from '../../../libs/actions/App';
-import Permissions from '../../../libs/Permissions';
+import AvatarWithImagePicker from '@components/AvatarWithImagePicker';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import * as UserUtils from '@libs/UserUtils';
+import userPropTypes from '@pages/settings/userPropTypes';
+import styles from '@styles/styles';
+import * as App from '@userActions/App';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/settings/Profile/PronounsPage.js b/src/pages/settings/Profile/PronounsPage.js
index 232b861a0f35..408da6376853 100644
--- a/src/pages/settings/Profile/PronounsPage.js
+++ b/src/pages/settings/Profile/PronounsPage.js
@@ -1,22 +1,22 @@
-import _ from 'underscore';
import lodashGet from 'lodash/get';
-import React, {useState, useMemo, useEffect} from 'react';
-import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import * as PersonalDetails from '../../../libs/actions/PersonalDetails';
-import CONST from '../../../CONST';
-import ROUTES from '../../../ROUTES';
-import Navigation from '../../../libs/Navigation/Navigation';
-import SelectionList from '../../../components/SelectionList';
-import useLocalize from '../../../hooks/useLocalize';
-import ONYXKEYS from '../../../ONYXKEYS';
-import FullScreenLoadingIndicator from '../../../components/FullscreenLoadingIndicator';
-import compose from '../../../libs/compose';
+import React, {useEffect, useMemo, useState} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import FullScreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withCurrentUserPersonalDetailsPropTypes,
diff --git a/src/pages/settings/Profile/TimezoneInitialPage.js b/src/pages/settings/Profile/TimezoneInitialPage.js
index 5fd5e1bd7661..d2dec7195087 100644
--- a/src/pages/settings/Profile/TimezoneInitialPage.js
+++ b/src/pages/settings/Profile/TimezoneInitialPage.js
@@ -1,19 +1,19 @@
import lodashGet from 'lodash/get';
import React from 'react';
import {View} from 'react-native';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import ROUTES from '../../../ROUTES';
-import CONST from '../../../CONST';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import Navigation from '../../../libs/Navigation/Navigation';
-import * as PersonalDetails from '../../../libs/actions/PersonalDetails';
-import compose from '../../../libs/compose';
-import Switch from '../../../components/Switch';
-import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Switch from '@components/Switch';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Profile/TimezoneSelectPage.js b/src/pages/settings/Profile/TimezoneSelectPage.js
index 2c47acd58daa..2586be9fb673 100644
--- a/src/pages/settings/Profile/TimezoneSelectPage.js
+++ b/src/pages/settings/Profile/TimezoneSelectPage.js
@@ -1,16 +1,17 @@
import lodashGet from 'lodash/get';
-import React, {useState, useRef} from 'react';
+import React, {useState} from 'react';
import _ from 'underscore';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsPropTypes, withCurrentUserPersonalDetailsDefaultProps} from '../../../components/withCurrentUserPersonalDetails';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import CONST from '../../../CONST';
-import TIMEZONES from '../../../TIMEZONES';
-import * as PersonalDetails from '../../../libs/actions/PersonalDetails';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import SelectionList from '../../../components/SelectionList';
-import useLocalize from '../../../hooks/useLocalize';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import useInitialValue from '@hooks/useInitialValue';
+import useLocalize from '@hooks/useLocalize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PersonalDetails from '@userActions/PersonalDetails';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
+import TIMEZONES from '@src/TIMEZONES';
const propTypes = {
...withCurrentUserPersonalDetailsPropTypes,
@@ -36,7 +37,7 @@ const getUserTimezone = (currentUserPersonalDetails) => lodashGet(currentUserPer
function TimezoneSelectPage(props) {
const {translate} = useLocalize();
const timezone = getUserTimezone(props.currentUserPersonalDetails);
- const allTimezones = useRef(
+ const allTimezones = useInitialValue(() =>
_.chain(TIMEZONES)
.filter((tz) => !tz.startsWith('Etc/GMT'))
.map((text) => ({
@@ -47,7 +48,7 @@ function TimezoneSelectPage(props) {
.value(),
);
const [timezoneInputText, setTimezoneInputText] = useState('');
- const [timezoneOptions, setTimezoneOptions] = useState(allTimezones.current);
+ const [timezoneOptions, setTimezoneOptions] = useState(allTimezones);
/**
* @param {Object} timezone
@@ -64,7 +65,7 @@ function TimezoneSelectPage(props) {
setTimezoneInputText(searchText);
const searchWords = searchText.toLowerCase().match(/[a-z0-9]+/g) || [];
setTimezoneOptions(
- _.filter(allTimezones.current, (tz) =>
+ _.filter(allTimezones, (tz) =>
_.every(
searchWords,
(word) =>
diff --git a/src/pages/settings/Report/NotificationPreferencePage.js b/src/pages/settings/Report/NotificationPreferencePage.js
index 43e346150ca8..75e9e0d5c5e8 100644
--- a/src/pages/settings/Report/NotificationPreferencePage.js
+++ b/src/pages/settings/Report/NotificationPreferencePage.js
@@ -1,18 +1,18 @@
import React from 'react';
import _ from 'underscore';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Navigation from '../../../libs/Navigation/Navigation';
-import compose from '../../../libs/compose';
-import withReportOrNotFound from '../../home/report/withReportOrNotFound';
-import FullPageNotFoundView from '../../../components/BlockingViews/FullPageNotFoundView';
-import reportPropTypes from '../../reportPropTypes';
-import ROUTES from '../../../ROUTES';
-import CONST from '../../../CONST';
-import * as Report from '../../../libs/actions/Report';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import SelectionList from '../../../components/SelectionList';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import withReportOrNotFound from '@pages/home/report/withReportOrNotFound';
+import reportPropTypes from '@pages/reportPropTypes';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Report/ReportSettingsPage.js b/src/pages/settings/Report/ReportSettingsPage.js
index fb88cbd59f25..df23e16e80cd 100644
--- a/src/pages/settings/Report/ReportSettingsPage.js
+++ b/src/pages/settings/Report/ReportSettingsPage.js
@@ -1,29 +1,29 @@
-import React, {useMemo} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import {View, ScrollView} from 'react-native';
+import React, {useMemo} from 'react';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import CONST from '../../../CONST';
-import ONYXKEYS from '../../../ONYXKEYS';
-import styles from '../../../styles/styles';
-import compose from '../../../libs/compose';
-import Navigation from '../../../libs/Navigation/Navigation';
-import * as Report from '../../../libs/actions/Report';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import useLocalize from '../../../hooks/useLocalize';
-import Text from '../../../components/Text';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import reportPropTypes from '../../reportPropTypes';
-import withReportOrNotFound from '../../home/report/withReportOrNotFound';
-import FullPageNotFoundView from '../../../components/BlockingViews/FullPageNotFoundView';
-import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription';
-import ROUTES from '../../../ROUTES';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import MenuItem from '../../../components/MenuItem';
-import DisplayNames from '../../../components/DisplayNames';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import DisplayNames from '@components/DisplayNames';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import withReportOrNotFound from '@pages/home/report/withReportOrNotFound';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Route params */
diff --git a/src/pages/settings/Report/RoomNamePage.js b/src/pages/settings/Report/RoomNamePage.js
index 4ce997533378..2ff9b1f1108f 100644
--- a/src/pages/settings/Report/RoomNamePage.js
+++ b/src/pages/settings/Report/RoomNamePage.js
@@ -1,26 +1,26 @@
-import React, {useCallback, useRef} from 'react';
-import {withOnyx} from 'react-native-onyx';
+import {useIsFocused} from '@react-navigation/native';
import PropTypes from 'prop-types';
+import React, {useCallback, useRef} from 'react';
import {View} from 'react-native';
-import {useIsFocused} from '@react-navigation/native';
-import CONST from '../../../CONST';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Form from '../../../components/Form';
-import ONYXKEYS from '../../../ONYXKEYS';
-import styles from '../../../styles/styles';
-import Navigation from '../../../libs/Navigation/Navigation';
-import compose from '../../../libs/compose';
-import * as ErrorUtils from '../../../libs/ErrorUtils';
-import * as ValidationUtils from '../../../libs/ValidationUtils';
-import withReportOrNotFound from '../../home/report/withReportOrNotFound';
-import reportPropTypes from '../../reportPropTypes';
-import ROUTES from '../../../ROUTES';
-import * as Report from '../../../libs/actions/Report';
-import RoomNameInput from '../../../components/RoomNameInput';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import FullPageNotFoundView from '../../../components/BlockingViews/FullPageNotFoundView';
+import {withOnyx} from 'react-native-onyx';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import RoomNameInput from '@components/RoomNameInput';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import withReportOrNotFound from '@pages/home/report/withReportOrNotFound';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Report/WriteCapabilityPage.js b/src/pages/settings/Report/WriteCapabilityPage.js
index 174cc57d8d18..c1b417bc28bd 100644
--- a/src/pages/settings/Report/WriteCapabilityPage.js
+++ b/src/pages/settings/Report/WriteCapabilityPage.js
@@ -1,22 +1,22 @@
import React from 'react';
-import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import CONST from '../../../CONST';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Navigation from '../../../libs/Navigation/Navigation';
-import compose from '../../../libs/compose';
-import withReportOrNotFound from '../../home/report/withReportOrNotFound';
-import reportPropTypes from '../../reportPropTypes';
-import ROUTES from '../../../ROUTES';
-import * as Report from '../../../libs/actions/Report';
-import * as ReportUtils from '../../../libs/ReportUtils';
-import FullPageNotFoundView from '../../../components/BlockingViews/FullPageNotFoundView';
-import * as PolicyUtils from '../../../libs/PolicyUtils';
-import {policyPropTypes, policyDefaultProps} from '../../workspace/withPolicy';
-import SelectionList from '../../../components/SelectionList';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import withReportOrNotFound from '@pages/home/report/withReportOrNotFound';
+import reportPropTypes from '@pages/reportPropTypes';
+import {policyDefaultProps, policyPropTypes} from '@pages/workspace/withPolicy';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/settings/Security/CloseAccountPage.js b/src/pages/settings/Security/CloseAccountPage.js
index 763f6c77d774..da4cd7b60e2a 100644
--- a/src/pages/settings/Security/CloseAccountPage.js
+++ b/src/pages/settings/Security/CloseAccountPage.js
@@ -1,26 +1,26 @@
-import React, {useState, useEffect} from 'react';
+import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
+import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import Str from 'expensify-common/lib/str';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import * as User from '../../../libs/actions/User';
-import compose from '../../../libs/compose';
-import styles from '../../../styles/styles';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import TextInput from '../../../components/TextInput';
-import Text from '../../../components/Text';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import * as CloseAccount from '../../../libs/actions/CloseAccount';
-import ONYXKEYS from '../../../ONYXKEYS';
-import CONST from '../../../CONST';
-import ConfirmModal from '../../../components/ConfirmModal';
-import * as ValidationUtils from '../../../libs/ValidationUtils';
-import FormProvider from '../../../components/Form/FormProvider';
-import InputWrapper from '../../../components/Form/InputWrapper';
+import ConfirmModal from '@components/ConfirmModal';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as CloseAccount from '@userActions/CloseAccount';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Session of currently logged in user */
diff --git a/src/pages/settings/Security/SecuritySettingsPage.js b/src/pages/settings/Security/SecuritySettingsPage.js
index 704ea17422bd..1bd6310ec97f 100644
--- a/src/pages/settings/Security/SecuritySettingsPage.js
+++ b/src/pages/settings/Security/SecuritySettingsPage.js
@@ -1,20 +1,21 @@
-import _ from 'underscore';
-import React from 'react';
-import {View, ScrollView} from 'react-native';
-import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import SCREENS from '../../../SCREENS';
-import styles from '../../../styles/styles';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import themeColors from '../../../styles/themes/default';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import MenuItem from '../../../components/MenuItem';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
-import IllustratedHeaderPageLayout from '../../../components/IllustratedHeaderPageLayout';
-import * as LottieAnimations from '../../../components/LottieAnimations';
+import React, {useMemo} from 'react';
+import {ScrollView, View} from 'react-native';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import * as Expensicons from '@components/Icon/Expensicons';
+import IllustratedHeaderPageLayout from '@components/IllustratedHeaderPageLayout';
+import * as LottieAnimations from '@components/LottieAnimations';
+import MenuItemList from '@components/MenuItemList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useWaitForNavigation from '@hooks/useWaitForNavigation';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
const propTypes = {
...withLocalizePropTypes,
@@ -33,24 +34,36 @@ const defaultProps = {
};
function SecuritySettingsPage(props) {
- const menuItems = [
- {
- translationKey: 'twoFactorAuth.headerTitle',
- icon: Expensicons.Shield,
- action: () => Navigation.navigate(ROUTES.SETTINGS_2FA),
- },
- {
- translationKey: 'closeAccountPage.closeAccount',
- icon: Expensicons.ClosedSign,
- action: () => {
- Navigation.navigate(ROUTES.SETTINGS_CLOSE);
+ const {translate} = props;
+ const waitForNavigate = useWaitForNavigation();
+
+ const menuItems = useMemo(() => {
+ const baseMenuItems = [
+ {
+ translationKey: 'twoFactorAuth.headerTitle',
+ icon: Expensicons.Shield,
+ action: waitForNavigate(() => Navigation.navigate(ROUTES.SETTINGS_2FA)),
+ },
+ {
+ translationKey: 'closeAccountPage.closeAccount',
+ icon: Expensicons.ClosedSign,
+ action: waitForNavigate(() => Navigation.navigate(ROUTES.SETTINGS_CLOSE)),
},
- },
- ];
+ ];
+
+ return _.map(baseMenuItems, (item) => ({
+ key: item.translationKey,
+ title: translate(item.translationKey),
+ icon: item.icon,
+ iconRight: item.iconRight,
+ onPress: item.action,
+ shouldShowRightIcon: true,
+ }));
+ }, [translate, waitForNavigate]);
return (
Navigation.goBack(ROUTES.SETTINGS)}
shouldShowBackButton
illustration={LottieAnimations.Safe}
@@ -58,16 +71,10 @@ function SecuritySettingsPage(props) {
>
- {_.map(menuItems, (item) => (
- item.action()}
- shouldShowRightIcon
- />
- ))}
+
diff --git a/src/pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper.js b/src/pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper.js
index 64aa64d07ee5..98df839ce31e 100644
--- a/src/pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper.js
+++ b/src/pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper.js
@@ -1,12 +1,12 @@
import React from 'react';
-import HeaderWithBackButton from '../../../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../../../components/ScreenWrapper';
-import FullPageOfflineBlockingView from '../../../../../components/BlockingViews/FullPageOfflineBlockingView';
-import * as TwoFactorAuthActions from '../../../../../libs/actions/TwoFactorAuthActions';
+import AnimatedStep from '@components/AnimatedStep';
+import useAnimatedStepContext from '@components/AnimatedStep/useAnimatedStepContext';
+import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import styles from '@styles/styles';
+import * as TwoFactorAuthActions from '@userActions/TwoFactorAuthActions';
import StepWrapperPropTypes from './StepWrapperPropTypes';
-import AnimatedStep from '../../../../../components/AnimatedStep';
-import styles from '../../../../../styles/styles';
-import useAnimatedStepContext from '../../../../../components/AnimatedStep/useAnimatedStepContext';
function StepWrapper({
title = '',
diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js
index ebad8d8bc5d0..6d74a0f91bd9 100644
--- a/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js
+++ b/src/pages/settings/Security/TwoFactorAuth/Steps/CodesStep.js
@@ -1,28 +1,28 @@
import React, {useEffect, useState} from 'react';
+import {ActivityIndicator, ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import {ActivityIndicator, View, ScrollView} from 'react-native';
import _ from 'underscore';
-import * as Expensicons from '../../../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../../../components/Icon/Illustrations';
-import styles from '../../../../../styles/styles';
-import FixedFooter from '../../../../../components/FixedFooter';
-import Button from '../../../../../components/Button';
-import PressableWithDelayToggle from '../../../../../components/Pressable/PressableWithDelayToggle';
-import Text from '../../../../../components/Text';
-import Section from '../../../../../components/Section';
-import ONYXKEYS from '../../../../../ONYXKEYS';
-import Clipboard from '../../../../../libs/Clipboard';
-import themeColors from '../../../../../styles/themes/default';
-import localFileDownload from '../../../../../libs/localFileDownload';
-import * as Session from '../../../../../libs/actions/Session';
-import CONST from '../../../../../CONST';
-import useTwoFactorAuthContext from '../TwoFactorAuthContext/useTwoFactorAuth';
-import useLocalize from '../../../../../hooks/useLocalize';
-import useWindowDimensions from '../../../../../hooks/useWindowDimensions';
-import StepWrapper from '../StepWrapper/StepWrapper';
-import {defaultAccount, TwoFactorAuthPropTypes} from '../TwoFactorAuthPropTypes';
-import * as TwoFactorAuthActions from '../../../../../libs/actions/TwoFactorAuthActions';
-import FormHelpMessage from '../../../../../components/FormHelpMessage';
+import Button from '@components/Button';
+import FixedFooter from '@components/FixedFooter';
+import FormHelpMessage from '@components/FormHelpMessage';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import PressableWithDelayToggle from '@components/Pressable/PressableWithDelayToggle';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import Clipboard from '@libs/Clipboard';
+import localFileDownload from '@libs/localFileDownload';
+import StepWrapper from '@pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper';
+import useTwoFactorAuthContext from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthContext/useTwoFactorAuth';
+import {defaultAccount, TwoFactorAuthPropTypes} from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as Session from '@userActions/Session';
+import * as TwoFactorAuthActions from '@userActions/TwoFactorAuthActions';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
function CodesStep({account = defaultAccount}) {
const {translate} = useLocalize();
diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/DisabledStep.js b/src/pages/settings/Security/TwoFactorAuth/Steps/DisabledStep.js
index 2f3b87e69a6e..317e510024b0 100644
--- a/src/pages/settings/Security/TwoFactorAuth/Steps/DisabledStep.js
+++ b/src/pages/settings/Security/TwoFactorAuth/Steps/DisabledStep.js
@@ -1,13 +1,13 @@
import React from 'react';
-import * as Illustrations from '../../../../../components/Icon/Illustrations';
-import styles from '../../../../../styles/styles';
-import BlockingView from '../../../../../components/BlockingViews/BlockingView';
-import FixedFooter from '../../../../../components/FixedFooter';
-import Button from '../../../../../components/Button';
-import variables from '../../../../../styles/variables';
-import StepWrapper from '../StepWrapper/StepWrapper';
-import useLocalize from '../../../../../hooks/useLocalize';
-import * as TwoFactorAuthActions from '../../../../../libs/actions/TwoFactorAuthActions';
+import BlockingView from '@components/BlockingViews/BlockingView';
+import Button from '@components/Button';
+import FixedFooter from '@components/FixedFooter';
+import * as Illustrations from '@components/Icon/Illustrations';
+import useLocalize from '@hooks/useLocalize';
+import StepWrapper from '@pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import * as TwoFactorAuthActions from '@userActions/TwoFactorAuthActions';
function DisabledStep() {
const {translate} = useLocalize();
diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/EnabledStep.js b/src/pages/settings/Security/TwoFactorAuth/Steps/EnabledStep.js
index 584d6195bbe6..6b0edfc49da3 100644
--- a/src/pages/settings/Security/TwoFactorAuth/Steps/EnabledStep.js
+++ b/src/pages/settings/Security/TwoFactorAuth/Steps/EnabledStep.js
@@ -1,16 +1,16 @@
import React, {useState} from 'react';
-import {Text, View, ScrollView} from 'react-native';
-import Section from '../../../../../components/Section';
-import * as Illustrations from '../../../../../components/Icon/Illustrations';
-import * as Expensicons from '../../../../../components/Icon/Expensicons';
-import themeColors from '../../../../../styles/themes/default';
-import styles from '../../../../../styles/styles';
-import ConfirmModal from '../../../../../components/ConfirmModal';
-import * as Session from '../../../../../libs/actions/Session';
-import StepWrapper from '../StepWrapper/StepWrapper';
-import CONST from '../../../../../CONST';
-import useLocalize from '../../../../../hooks/useLocalize';
-import useTwoFactorAuthContext from '../TwoFactorAuthContext/useTwoFactorAuth';
+import {ScrollView, Text, View} from 'react-native';
+import ConfirmModal from '@components/ConfirmModal';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import useLocalize from '@hooks/useLocalize';
+import StepWrapper from '@pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper';
+import useTwoFactorAuthContext from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthContext/useTwoFactorAuth';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
function EnabledStep() {
const [isConfirmModalVisible, setIsConfirmModalVisible] = useState(false);
diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.js b/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.js
index 308efecf3415..76d5e8a19a46 100644
--- a/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.js
+++ b/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.js
@@ -1,11 +1,11 @@
import React from 'react';
-import ConfirmationPage from '../../../../../components/ConfirmationPage';
-import * as TwoFactorAuthActions from '../../../../../libs/actions/TwoFactorAuthActions';
-import * as LottieAnimations from '../../../../../components/LottieAnimations';
-import CONST from '../../../../../CONST';
-import StepWrapper from '../StepWrapper/StepWrapper';
-import useTwoFactorAuthContext from '../TwoFactorAuthContext/useTwoFactorAuth';
-import useLocalize from '../../../../../hooks/useLocalize';
+import ConfirmationPage from '@components/ConfirmationPage';
+import * as LottieAnimations from '@components/LottieAnimations';
+import useLocalize from '@hooks/useLocalize';
+import StepWrapper from '@pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper';
+import useTwoFactorAuthContext from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthContext/useTwoFactorAuth';
+import * as TwoFactorAuthActions from '@userActions/TwoFactorAuthActions';
+import CONST from '@src/CONST';
function SuccessStep() {
const {setStep} = useTwoFactorAuthContext();
diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/VerifyStep.js b/src/pages/settings/Security/TwoFactorAuth/Steps/VerifyStep.js
index 560a395e6844..440b40c5363c 100644
--- a/src/pages/settings/Security/TwoFactorAuth/Steps/VerifyStep.js
+++ b/src/pages/settings/Security/TwoFactorAuth/Steps/VerifyStep.js
@@ -1,25 +1,25 @@
+import PropTypes from 'prop-types';
import React, {useEffect} from 'react';
-import {withOnyx} from 'react-native-onyx';
import {ScrollView, View} from 'react-native';
-import PropTypes from 'prop-types';
-import * as Session from '../../../../../libs/actions/Session';
-import styles from '../../../../../styles/styles';
-import Button from '../../../../../components/Button';
-import Text from '../../../../../components/Text';
-import ONYXKEYS from '../../../../../ONYXKEYS';
-import TextLink from '../../../../../components/TextLink';
-import Clipboard from '../../../../../libs/Clipboard';
-import FixedFooter from '../../../../../components/FixedFooter';
-import * as Expensicons from '../../../../../components/Icon/Expensicons';
-import PressableWithDelayToggle from '../../../../../components/Pressable/PressableWithDelayToggle';
-import TwoFactorAuthForm from '../TwoFactorAuthForm';
-import QRCode from '../../../../../components/QRCode';
-import expensifyLogo from '../../../../../../assets/images/expensify-logo-round-transparent.png';
-import CONST from '../../../../../CONST';
-import StepWrapper from '../StepWrapper/StepWrapper';
-import useTwoFactorAuthContext from '../TwoFactorAuthContext/useTwoFactorAuth';
-import useLocalize from '../../../../../hooks/useLocalize';
-import {defaultAccount, TwoFactorAuthPropTypes} from '../TwoFactorAuthPropTypes';
+import {withOnyx} from 'react-native-onyx';
+import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png';
+import Button from '@components/Button';
+import FixedFooter from '@components/FixedFooter';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithDelayToggle from '@components/Pressable/PressableWithDelayToggle';
+import QRCode from '@components/QRCode';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import Clipboard from '@libs/Clipboard';
+import StepWrapper from '@pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper';
+import useTwoFactorAuthContext from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthContext/useTwoFactorAuth';
+import TwoFactorAuthForm from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm';
+import {defaultAccount, TwoFactorAuthPropTypes} from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthPropTypes';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const TROUBLESHOOTING_LINK = 'https://community.expensify.com/discussion/7736/faq-troubleshooting-two-factor-authentication-issues/p1?new=1';
@@ -118,23 +118,23 @@ function VerifyStep({account, session}) {
{translate('twoFactorAuth.enterCode')}
-
+
+
+
-
- {
- if (!formRef.current) {
- return;
- }
- formRef.current.validateAndSubmitForm();
- }}
- />
-
-
+ {
+ if (!formRef.current) {
+ return;
+ }
+ formRef.current.validateAndSubmitForm();
+ }}
+ />
+
);
}
diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.js b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.js
index 4c0bf81210b4..d441a6157049 100644
--- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.js
+++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/BaseTwoFactorAuthForm.js
@@ -1,13 +1,13 @@
-import React, {useCallback, useState, forwardRef, useImperativeHandle} from 'react';
import PropTypes from 'prop-types';
+import React, {forwardRef, useCallback, useImperativeHandle, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
-import MagicCodeInput from '../../../../../components/MagicCodeInput';
-import * as ErrorUtils from '../../../../../libs/ErrorUtils';
-import withLocalize, {withLocalizePropTypes} from '../../../../../components/withLocalize';
-import ONYXKEYS from '../../../../../ONYXKEYS';
-import compose from '../../../../../libs/compose';
-import * as ValidationUtils from '../../../../../libs/ValidationUtils';
-import * as Session from '../../../../../libs/actions/Session';
+import MagicCodeInput from '@components/MagicCodeInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import * as Session from '@userActions/Session';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
...withLocalizePropTypes,
@@ -103,17 +103,19 @@ function BaseTwoFactorAuthForm(props) {
BaseTwoFactorAuthForm.propTypes = propTypes;
BaseTwoFactorAuthForm.defaultProps = defaultProps;
+const BaseTwoFactorAuthFormWithRef = forwardRef((props, ref) => (
+
+));
+
+BaseTwoFactorAuthFormWithRef.displayName = 'BaseTwoFactorAuthFormWithRef';
+
export default compose(
withLocalize,
withOnyx({
account: {key: ONYXKEYS.ACCOUNT},
}),
-)(
- forwardRef((props, ref) => (
-
- )),
-);
+)(BaseTwoFactorAuthFormWithRef);
diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.android.js b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.android.js
index ba7bb2186aa6..5f71da7629dd 100644
--- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.android.js
+++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.android.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import BaseTwoFactorAuthForm from './BaseTwoFactorAuthForm';
const propTypes = {
diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.js b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.js
index 171322ecb32d..5d361c41e7e3 100644
--- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.js
+++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthForm/index.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import BaseTwoFactorAuthForm from './BaseTwoFactorAuthForm';
const propTypes = {
diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.js b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.js
index 99aeb4b11f89..99f57a5a5a9d 100644
--- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.js
+++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthPage.js
@@ -1,5 +1,5 @@
import React from 'react';
-import AnimatedStepProvider from '../../../../components/AnimatedStep/AnimatedStepProvider';
+import AnimatedStepProvider from '@components/AnimatedStep/AnimatedStepProvider';
import TwoFactorAuthSteps from './TwoFactorAuthSteps';
function TwoFactorAuthPage() {
diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.js b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.js
index df2a4d8e0950..31a33efa3996 100644
--- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.js
+++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.js
@@ -1,16 +1,16 @@
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {withOnyx} from 'react-native-onyx';
+import useAnimatedStepContext from '@components/AnimatedStep/useAnimatedStepContext';
+import * as TwoFactorAuthActions from '@userActions/TwoFactorAuthActions';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import CodesStep from './Steps/CodesStep';
import DisabledStep from './Steps/DisabledStep';
import EnabledStep from './Steps/EnabledStep';
-import VerifyStep from './Steps/VerifyStep';
import SuccessStep from './Steps/SuccessStep';
-import ONYXKEYS from '../../../../ONYXKEYS';
-import CONST from '../../../../CONST';
-import * as TwoFactorAuthActions from '../../../../libs/actions/TwoFactorAuthActions';
+import VerifyStep from './Steps/VerifyStep';
import TwoFactorAuthContext from './TwoFactorAuthContext';
import {defaultAccount, TwoFactorAuthPropTypes} from './TwoFactorAuthPropTypes';
-import useAnimatedStepContext from '../../../../components/AnimatedStep/useAnimatedStepContext';
function TwoFactorAuthSteps({account = defaultAccount}) {
const [currentStep, setCurrentStep] = useState(CONST.TWO_FACTOR_AUTH_STEPS.CODES);
diff --git a/src/pages/settings/Wallet/ActivatePhysicalCardPage.js b/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
index 0175f2ceac1f..b643f2c54ad3 100644
--- a/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
+++ b/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
@@ -1,31 +1,31 @@
-import React, {useRef, useCallback, useState, useEffect} from 'react';
-import {View} from 'react-native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import Text from '../../../components/Text';
-import Navigation from '../../../libs/Navigation/Navigation';
-import styles from '../../../styles/styles';
-import MagicCodeInput from '../../../components/MagicCodeInput';
-import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
-import * as ErrorUtils from '../../../libs/ErrorUtils';
-import * as CardSettings from '../../../libs/actions/Card';
-import BigNumberPad from '../../../components/BigNumberPad';
-import Button from '../../../components/Button';
-import IllustratedHeaderPageLayout from '../../../components/IllustratedHeaderPageLayout';
-import themeColors from '../../../styles/themes/default';
-import SCREENS from '../../../SCREENS';
-import * as LottieAnimations from '../../../components/LottieAnimations';
-import useWindowDimensions from '../../../hooks/useWindowDimensions';
-import ONYXKEYS from '../../../ONYXKEYS';
-import useLocalize from '../../../hooks/useLocalize';
-import ROUTES from '../../../ROUTES';
-import CONST from '../../../CONST';
+import BigNumberPad from '@components/BigNumberPad';
+import Button from '@components/Button';
+import IllustratedHeaderPageLayout from '@components/IllustratedHeaderPageLayout';
+import * as LottieAnimations from '@components/LottieAnimations';
+import MagicCodeInput from '@components/MagicCodeInput';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as CardUtils from '@libs/CardUtils';
+import * as DeviceCapabilities from '@libs/DeviceCapabilities';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as CardSettings from '@userActions/Card';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
import assignedCardPropTypes from './assignedCardPropTypes';
-import * as CardUtils from '../../../libs/CardUtils';
-import useNetwork from '../../../hooks/useNetwork';
-import NotFoundPage from '../../ErrorPage/NotFoundPage';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/settings/Wallet/AddDebitCardPage.js b/src/pages/settings/Wallet/AddDebitCardPage.js
index e75c3b2c517e..ff20d518ff5d 100644
--- a/src/pages/settings/Wallet/AddDebitCardPage.js
+++ b/src/pages/settings/Wallet/AddDebitCardPage.js
@@ -1,27 +1,27 @@
+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 HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import styles from '../../../styles/styles';
-import Text from '../../../components/Text';
-import TextLink from '../../../components/TextLink';
-import useLocalize from '../../../hooks/useLocalize';
-import * as PaymentMethods from '../../../libs/actions/PaymentMethods';
-import * as ValidationUtils from '../../../libs/ValidationUtils';
-import CheckboxWithLabel from '../../../components/CheckboxWithLabel';
-import StatePicker from '../../../components/StatePicker';
-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';
-import NotFoundPage from '../../ErrorPage/NotFoundPage';
-import Permissions from '../../../libs/Permissions';
+import AddressSearch from '@components/AddressSearch';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import StatePicker from '@components/StatePicker';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import TextLink from '@components/TextLink';
+import useLocalize from '@hooks/useLocalize';
+import usePrevious from '@hooks/usePrevious';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import styles from '@styles/styles';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/settings/Wallet/ChooseTransferAccountPage.js b/src/pages/settings/Wallet/ChooseTransferAccountPage.js
index 78a9e92326bc..a44e21390b80 100644
--- a/src/pages/settings/Wallet/ChooseTransferAccountPage.js
+++ b/src/pages/settings/Wallet/ChooseTransferAccountPage.js
@@ -1,21 +1,21 @@
import React from 'react';
-import {withOnyx} from 'react-native-onyx';
import {View} from 'react-native';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import Navigation from '../../../libs/Navigation/Navigation';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import CONST from '../../../CONST';
+import {withOnyx} from 'react-native-onyx';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import PaymentMethodList from './PaymentMethodList';
-import * as PaymentMethods from '../../../libs/actions/PaymentMethods';
-import ROUTES from '../../../ROUTES';
-import MenuItem from '../../../components/MenuItem';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
import walletTransferPropTypes from './walletTransferPropTypes';
-import styles from '../../../styles/styles';
-import * as BankAccounts from '../../../libs/actions/BankAccounts';
const propTypes = {
/** Wallet transfer propTypes */
diff --git a/src/pages/settings/Wallet/DangerCardSection.js b/src/pages/settings/Wallet/DangerCardSection.js
index bd67ba03c43b..40788753bce7 100644
--- a/src/pages/settings/Wallet/DangerCardSection.js
+++ b/src/pages/settings/Wallet/DangerCardSection.js
@@ -1,9 +1,9 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import styles from '../../../styles/styles';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Text from '../../../components/Text';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Text from '@components/Text';
+import styles from '@styles/styles';
const propTypes = {
title: PropTypes.string.isRequired,
diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.js b/src/pages/settings/Wallet/ExpensifyCardPage.js
index e198d449d57d..d6cdbefc471a 100644
--- a/src/pages/settings/Wallet/ExpensifyCardPage.js
+++ b/src/pages/settings/Wallet/ExpensifyCardPage.js
@@ -3,28 +3,30 @@ import React, {useState} from 'react';
import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import ONYXKEYS from '../../../ONYXKEYS';
-import ROUTES from '../../../ROUTES';
-import NotFoundPage from '../../ErrorPage/NotFoundPage';
-import CardPreview from '../../../components/CardPreview';
-import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
-import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription';
-import ScreenWrapper from '../../../components/ScreenWrapper';
-import useLocalize from '../../../hooks/useLocalize';
-import * as CurrencyUtils from '../../../libs/CurrencyUtils';
-import Navigation from '../../../libs/Navigation/Navigation';
-import styles from '../../../styles/styles';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as CardUtils from '../../../libs/CardUtils';
-import Button from '../../../components/Button';
-import CardDetails from './WalletPage/CardDetails';
-import MenuItem from '../../../components/MenuItem';
-import CONST from '../../../CONST';
+import Button from '@components/Button';
+import CardPreview from '@components/CardPreview';
+import DotIndicatorMessage from '@components/DotIndicatorMessage';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import * as CardUtils from '@libs/CardUtils';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
+import styles from '@styles/styles';
+import theme from '@styles/themes/default';
+import * as Card from '@userActions/Card';
+import * as Link from '@userActions/Link';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import assignedCardPropTypes from './assignedCardPropTypes';
-import theme from '../../../styles/themes/default';
-import DotIndicatorMessage from '../../../components/DotIndicatorMessage';
-import * as Link from '../../../libs/actions/Link';
import DangerCardSection from './DangerCardSection';
+import CardDetails from './WalletPage/CardDetails';
const propTypes = {
/* Onyx Props */
@@ -50,12 +52,14 @@ function ExpensifyCardPage({
params: {domain},
},
}) {
+ const {isOffline} = useNetwork();
const {translate} = useLocalize();
const domainCards = CardUtils.getDomainCards(cardList)[domain];
const virtualCard = _.find(domainCards, (card) => card.isVirtual) || {};
const physicalCard = _.find(domainCards, (card) => !card.isVirtual) || {};
- const [shouldShowCardDetails, setShouldShowCardDetails] = useState(false);
+ const [isLoading, setIsLoading] = useState(false);
+ const [details, setDetails] = useState({});
if (_.isEmpty(virtualCard) && _.isEmpty(physicalCard)) {
return ;
@@ -64,7 +68,14 @@ function ExpensifyCardPage({
const formattedAvailableSpendAmount = CurrencyUtils.convertToDisplayString(physicalCard.availableSpend || virtualCard.availableSpend || 0);
const handleRevealDetails = () => {
- setShouldShowCardDetails(true);
+ setIsLoading(true);
+ // We can't store the response in Onyx for security reasons.
+ // That is this action is handled manually and the response is stored in a local state
+ // Hence the eslint disable here.
+ // eslint-disable-next-line rulesdir/no-thenable-actions-in-views
+ Card.revealVirtualCardDetails(virtualCard.cardID)
+ .then(setDetails)
+ .finally(() => setIsLoading(false));
};
const hasDetectedDomainFraud = _.some(domainCards, (card) => card.fraud === CONST.EXPENSIFY_CARD.FRAUD_TYPES.DOMAIN);
@@ -97,6 +108,32 @@ function ExpensifyCardPage({
{hasDetectedIndividualFraud && !hasDetectedDomainFraud ? (
<>
+ {details.pan ? (
+
+ ) : (
+
+ }
+ />
+ )}
{!_.isEmpty(virtualCard) && (
<>
- {shouldShowCardDetails ? (
+ {details.pan ? (
) : (
@@ -143,6 +180,8 @@ function ExpensifyCardPage({
medium
text={translate('cardPage.cardDetails.revealDetails')}
onPress={handleRevealDetails}
+ isDisabled={isLoading || isOffline}
+ isLoading={isLoading}
/>
}
/>
diff --git a/src/pages/settings/Wallet/PaymentMethodList.js b/src/pages/settings/Wallet/PaymentMethodList.js
index 3aacf45bfe19..5ba521e94412 100644
--- a/src/pages/settings/Wallet/PaymentMethodList.js
+++ b/src/pages/settings/Wallet/PaymentMethodList.js
@@ -1,33 +1,34 @@
-import _ from 'underscore';
-import React, {useCallback, useMemo} from 'react';
-import PropTypes from 'prop-types';
-import {FlatList} from 'react-native';
+import {FlashList} from '@shopify/flash-list';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useMemo} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import {withNetwork} from '../../../components/OnyxProvider';
-import styles from '../../../styles/styles';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import MenuItem from '../../../components/MenuItem';
-import Button from '../../../components/Button';
-import Text from '../../../components/Text';
-import compose from '../../../libs/compose';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import ONYXKEYS from '../../../ONYXKEYS';
-import CONST from '../../../CONST';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import bankAccountPropTypes from '../../../components/bankAccountPropTypes';
-import cardPropTypes from '../../../components/cardPropTypes';
-import * as PaymentUtils from '../../../libs/PaymentUtils';
-import FormAlertWrapper from '../../../components/FormAlertWrapper';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import * as PaymentMethods from '../../../libs/actions/PaymentMethods';
-import Log from '../../../libs/Log';
-import stylePropTypes from '../../../styles/stylePropTypes';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import getBankIcon from '../../../components/Icon/BankIcons';
+import _ from 'underscore';
+import bankAccountPropTypes from '@components/bankAccountPropTypes';
+import Button from '@components/Button';
+import cardPropTypes from '@components/cardPropTypes';
+import FormAlertWrapper from '@components/FormAlertWrapper';
+import getBankIcon from '@components/Icon/BankIcons';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import * as CardUtils from '@libs/CardUtils';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PaymentUtils from '@libs/PaymentUtils';
+import stylePropTypes from '@styles/stylePropTypes';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
+import * as PaymentMethods from '@userActions/PaymentMethods';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import assignedCardPropTypes from './assignedCardPropTypes';
-import * as CardUtils from '../../../libs/CardUtils';
const propTypes = {
/** What to do when a menu item is pressed */
@@ -84,6 +85,9 @@ const propTypes = {
/** Callback for whenever FlatList component size changes */
onListContentSizeChange: PropTypes.func,
+ /** Should menu items be selectable with a checkbox */
+ shouldShowSelectedState: PropTypes.bool,
+
/** React ref being forwarded to the PaymentMethodList Button */
buttonRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
@@ -92,8 +96,6 @@ const propTypes = {
/** List container style */
style: stylePropTypes,
-
- ...withLocalizePropTypes,
};
const defaultProps = {
@@ -118,6 +120,7 @@ const defaultProps = {
onListContentSizeChange: () => {},
shouldEnableScroll: true,
style: {},
+ shouldShowSelectedState: false,
};
/**
@@ -173,6 +176,15 @@ function shouldShowDefaultBadge(filteredPaymentMethods, isDefault = false) {
function isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, paymentMethod) {
return paymentMethod.accountType === actionPaymentMethodType && paymentMethod.methodID === activePaymentMethodID;
}
+
+/**
+ * @param {Object} item
+ * @returns {String}
+ */
+function keyExtractor(item) {
+ return item.key;
+}
+
function PaymentMethodList({
actionPaymentMethodType,
activePaymentMethodID,
@@ -182,23 +194,22 @@ function PaymentMethodList({
fundList,
filterType,
isLoadingPaymentMethods,
- listHeaderComponent,
- network,
- onListContentSizeChange,
onPress,
- shouldEnableScroll,
shouldShowSelectedState,
shouldShowAddPaymentMethodButton,
shouldShowAddBankAccount,
shouldShowEmptyListMessage,
shouldShowAssignedCards,
selectedMethodID,
+ listHeaderComponent,
+ onListContentSizeChange,
+ shouldEnableScroll,
style,
- translate,
}) {
- const filteredPaymentMethods = useMemo(() => {
- const paymentCardList = fundList || {};
+ const {translate} = useLocalize();
+ const {isOffline} = useNetwork();
+ const filteredPaymentMethods = useMemo(() => {
if (shouldShowAssignedCards) {
const assignedCards = _.chain(cardList)
// Filter by physical, active cards associated with a domain
@@ -229,6 +240,8 @@ function PaymentMethodList({
});
}
+ const paymentCardList = fundList || {};
+
// Hide any billing cards that are not P2P debit cards for now because you cannot make them your default method, or delete them
const filteredCardList = _.filter(paymentCardList, (card) => card.accountData.additionalData.isP2PDebitCard);
let combinedPaymentMethods = PaymentUtils.formatPaymentMethods(bankAccountList, filteredCardList);
@@ -237,25 +250,27 @@ function PaymentMethodList({
combinedPaymentMethods = _.filter(combinedPaymentMethods, (paymentMethod) => paymentMethod.accountType === filterType);
}
- if (!network.isOffline) {
+ if (!isOffline) {
combinedPaymentMethods = _.filter(
combinedPaymentMethods,
(paymentMethod) => paymentMethod.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE || !_.isEmpty(paymentMethod.errors),
);
}
- combinedPaymentMethods = _.map(combinedPaymentMethods, (paymentMethod) => ({
- ...paymentMethod,
- onPress: (e) => onPress(e, paymentMethod.accountType, paymentMethod.accountData, paymentMethod.isDefault, paymentMethod.methodID),
- iconFill: isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, paymentMethod) ? StyleUtils.getIconFillColor(CONST.BUTTON_STATES.PRESSED) : null,
- wrapperStyle: isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, paymentMethod)
- ? [StyleUtils.getButtonBackgroundColorStyle(CONST.BUTTON_STATES.PRESSED)]
- : null,
- disabled: paymentMethod.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
- }));
+ combinedPaymentMethods = _.map(combinedPaymentMethods, (paymentMethod) => {
+ const isMethodActive = isPaymentMethodActive(actionPaymentMethodType, activePaymentMethodID, paymentMethod);
+
+ return {
+ ...paymentMethod,
+ onPress: (e) => onPress(e, paymentMethod.accountType, paymentMethod.accountData, paymentMethod.isDefault, paymentMethod.methodID),
+ iconFill: isMethodActive ? StyleUtils.getIconFillColor(CONST.BUTTON_STATES.PRESSED) : null,
+ wrapperStyle: isMethodActive ? [StyleUtils.getButtonBackgroundColorStyle(CONST.BUTTON_STATES.PRESSED)] : null,
+ disabled: paymentMethod.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE,
+ };
+ });
return combinedPaymentMethods;
- }, [fundList, shouldShowAssignedCards, bankAccountList, filterType, network.isOffline, cardList, translate, actionPaymentMethodType, activePaymentMethodID, onPress]);
+ }, [shouldShowAssignedCards, fundList, bankAccountList, filterType, isOffline, cardList, translate, actionPaymentMethodType, activePaymentMethodID, onPress]);
/**
* Render placeholder when there are no payments methods
@@ -318,25 +333,27 @@ function PaymentMethodList({
return (
<>
- item.key}
- ListEmptyComponent={shouldShowEmptyListMessage ? renderListEmptyComponent : null}
- ListHeaderComponent={listHeaderComponent}
- ListFooterComponent={shouldShowAddBankAccount ? renderListFooterComponent : null}
- onContentSizeChange={onListContentSizeChange}
- scrollEnabled={shouldEnableScroll}
- style={style}
- />
+
+
+
{shouldShowAddPaymentMethodButton && (
- {(isOffline) => (
+ {(isFormOffline) => (
;
diff --git a/src/pages/signin/ChangeExpensifyLoginLink.js b/src/pages/signin/ChangeExpensifyLoginLink.js
index c152a903fbef..f5e526964333 100755
--- a/src/pages/signin/ChangeExpensifyLoginLink.js
+++ b/src/pages/signin/ChangeExpensifyLoginLink.js
@@ -1,15 +1,15 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import Text from '../../components/Text';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback';
-import CONST from '../../CONST';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The credentials of the logged in person */
diff --git a/src/pages/signin/ChooseSSOOrMagicCode.js b/src/pages/signin/ChooseSSOOrMagicCode.js
index 32f0776cdbc9..fd3ec85c5cb2 100644
--- a/src/pages/signin/ChooseSSOOrMagicCode.js
+++ b/src/pages/signin/ChooseSSOOrMagicCode.js
@@ -1,23 +1,23 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import Text from '../../components/Text';
-import Button from '../../components/Button';
-import * as Session from '../../libs/actions/Session';
+import Button from '@components/Button';
+import FormHelpMessage from '@components/FormHelpMessage';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import ChangeExpensifyLoginLink from './ChangeExpensifyLoginLink';
import Terms from './Terms';
-import CONST from '../../CONST';
-import ROUTES from '../../ROUTES';
-import Navigation from '../../libs/Navigation/Navigation';
-import * as ErrorUtils from '../../libs/ErrorUtils';
-import useLocalize from '../../hooks/useLocalize';
-import useNetwork from '../../hooks/useNetwork';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import FormHelpMessage from '../../components/FormHelpMessage';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/signin/DesktopRedirectPage.js b/src/pages/signin/DesktopRedirectPage.js
index ef6421da23bd..1c2521be09e2 100644
--- a/src/pages/signin/DesktopRedirectPage.js
+++ b/src/pages/signin/DesktopRedirectPage.js
@@ -1,6 +1,6 @@
import React from 'react';
-import * as App from '../../libs/actions/App';
-import DeeplinkRedirectLoadingIndicator from '../../components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator';
+import DeeplinkRedirectLoadingIndicator from '@components/DeeplinkWrapper/DeeplinkRedirectLoadingIndicator';
+import * as App from '@userActions/App';
/**
* Landing page for when a user enters third party login flow on desktop.
diff --git a/src/pages/signin/DesktopSignInRedirectPage/index.website.js b/src/pages/signin/DesktopSignInRedirectPage/index.website.js
index bec9b5107359..1536b45cf667 100644
--- a/src/pages/signin/DesktopSignInRedirectPage/index.website.js
+++ b/src/pages/signin/DesktopSignInRedirectPage/index.website.js
@@ -1,5 +1,5 @@
import React from 'react';
-import DesktopRedirectPage from '../DesktopRedirectPage';
+import DesktopRedirectPage from '@pages/signin/DesktopRedirectPage';
function DesktopSignInRedirectPage() {
return ;
diff --git a/src/pages/signin/EmailDeliveryFailurePage.js b/src/pages/signin/EmailDeliveryFailurePage.js
index 5d56980a2b97..a7b690a6151a 100644
--- a/src/pages/signin/EmailDeliveryFailurePage.js
+++ b/src/pages/signin/EmailDeliveryFailurePage.js
@@ -1,17 +1,17 @@
+import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
import React, {useEffect} from 'react';
import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import Str from 'expensify-common/lib/str';
-import styles from '../../styles/styles';
-import Text from '../../components/Text';
-import TextLink from '../../components/TextLink';
-import ONYXKEYS from '../../ONYXKEYS';
-import useLocalize from '../../hooks/useLocalize';
-import useKeyboardState from '../../hooks/useKeyboardState';
-import redirectToSignIn from '../../libs/actions/SignInRedirect';
-import CONST from '../../CONST';
-import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import useKeyboardState from '@hooks/useKeyboardState';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import redirectToSignIn from '@userActions/SignInRedirect';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/signin/GoogleSignInDesktopPage/index.website.js b/src/pages/signin/GoogleSignInDesktopPage/index.website.js
index 691b82448e31..b9451460dfb0 100644
--- a/src/pages/signin/GoogleSignInDesktopPage/index.website.js
+++ b/src/pages/signin/GoogleSignInDesktopPage/index.website.js
@@ -1,6 +1,6 @@
import React from 'react';
-import ThirdPartySignInPage from '../ThirdPartySignInPage';
-import CONST from '../../../CONST';
+import ThirdPartySignInPage from '@pages/signin/ThirdPartySignInPage';
+import CONST from '@src/CONST';
function GoogleSignInDesktopPage() {
return ;
diff --git a/src/pages/signin/Licenses.js b/src/pages/signin/Licenses.js
index e3f1026c1e9f..b73d1ad8c47d 100644
--- a/src/pages/signin/Licenses.js
+++ b/src/pages/signin/Licenses.js
@@ -1,11 +1,11 @@
import React from 'react';
import {View} from 'react-native';
-import styles from '../../styles/styles';
-import CONST from '../../CONST';
-import Text from '../../components/Text';
-import TextLink from '../../components/TextLink';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import LocalePicker from '../../components/LocalePicker';
+import LocalePicker from '@components/LocalePicker';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const currentYear = new Date().getFullYear();
diff --git a/src/pages/signin/LoginForm/BaseLoginForm.js b/src/pages/signin/LoginForm/BaseLoginForm.js
index 6270e6982e6e..9529d7fd0d60 100644
--- a/src/pages/signin/LoginForm/BaseLoginForm.js
+++ b/src/pages/signin/LoginForm/BaseLoginForm.js
@@ -1,38 +1,38 @@
+import {parsePhoneNumber} from 'awesome-phonenumber';
+import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import Str from 'expensify-common/lib/str';
-import {parsePhoneNumber} from 'awesome-phonenumber';
-import styles from '../../../styles/styles';
-import Text from '../../../components/Text';
-import * as Session from '../../../libs/actions/Session';
-import ONYXKEYS from '../../../ONYXKEYS';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import compose from '../../../libs/compose';
-import canFocusInputOnScreenFocus from '../../../libs/canFocusInputOnScreenFocus';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import TextInput from '../../../components/TextInput';
-import * as ValidationUtils from '../../../libs/ValidationUtils';
-import * as LoginUtils from '../../../libs/LoginUtils';
-import withToggleVisibilityView, {toggleVisibilityViewPropTypes} from '../../../components/withToggleVisibilityView';
-import FormAlertWithSubmitButton from '../../../components/FormAlertWithSubmitButton';
-import {withNetwork} from '../../../components/OnyxProvider';
-import networkPropTypes from '../../../components/networkPropTypes';
-import * as ErrorUtils from '../../../libs/ErrorUtils';
-import DotIndicatorMessage from '../../../components/DotIndicatorMessage';
-import * as CloseAccount from '../../../libs/actions/CloseAccount';
-import CONST from '../../../CONST';
-import CONFIG from '../../../CONFIG';
-import AppleSignIn from '../../../components/SignInButtons/AppleSignIn';
-import GoogleSignIn from '../../../components/SignInButtons/GoogleSignIn';
-import isInputAutoFilled from '../../../libs/isInputAutoFilled';
-import * as PolicyUtils from '../../../libs/PolicyUtils';
-import Log from '../../../libs/Log';
-import withNavigationFocus from '../../../components/withNavigationFocus';
-import usePrevious from '../../../hooks/usePrevious';
-import * as MemoryOnlyKeys from '../../../libs/actions/MemoryOnlyKeys/MemoryOnlyKeys';
+import DotIndicatorMessage from '@components/DotIndicatorMessage';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import AppleSignIn from '@components/SignInButtons/AppleSignIn';
+import GoogleSignIn from '@components/SignInButtons/GoogleSignIn';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withNavigationFocus from '@components/withNavigationFocus';
+import withToggleVisibilityView, {toggleVisibilityViewPropTypes} from '@components/withToggleVisibilityView';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import usePrevious from '@hooks/usePrevious';
+import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import isInputAutoFilled from '@libs/isInputAutoFilled';
+import Log from '@libs/Log';
+import * as LoginUtils from '@libs/LoginUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import styles from '@styles/styles';
+import * as CloseAccount from '@userActions/CloseAccount';
+import * as MemoryOnlyKeys from '@userActions/MemoryOnlyKeys/MemoryOnlyKeys';
+import * as Session from '@userActions/Session';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Should we dismiss the keyboard when transitioning away from the page? */
@@ -60,6 +60,12 @@ const propTypes = {
success: PropTypes.string,
}),
+ /** The credentials of the logged in person */
+ credentials: PropTypes.shape({
+ /** The email the user logged in with */
+ login: PropTypes.string,
+ }),
+
/** Props to detect online status */
network: networkPropTypes.isRequired,
@@ -78,6 +84,9 @@ const propTypes = {
const defaultProps = {
account: {},
+ credentials: {
+ login: '',
+ },
closeAccount: {},
blurOnSubmit: false,
innerRef: () => {},
@@ -86,7 +95,7 @@ const defaultProps = {
function LoginForm(props) {
const input = useRef();
- const [login, setLogin] = useState('');
+ const [login, setLogin] = useState(() => Str.removeSMSDomain(props.credentials.login || ''));
const [formError, setFormError] = useState(false);
const prevIsVisible = usePrevious(props.isVisible);
@@ -285,22 +294,25 @@ LoginForm.propTypes = propTypes;
LoginForm.defaultProps = defaultProps;
LoginForm.displayName = 'LoginForm';
+const LoginFormWithRef = forwardRef((props, ref) => (
+
+));
+
+LoginFormWithRef.displayName = 'LoginFormWithRef';
+
export default compose(
withNavigationFocus,
withOnyx({
account: {key: ONYXKEYS.ACCOUNT},
+ credentials: {key: ONYXKEYS.CREDENTIALS},
closeAccount: {key: ONYXKEYS.FORMS.CLOSE_ACCOUNT_FORM},
}),
withWindowDimensions,
withLocalize,
withToggleVisibilityView,
withNetwork(),
-)(
- forwardRef((props, ref) => (
-
- )),
-);
+)(LoginFormWithRef);
diff --git a/src/pages/signin/LoginForm/index.js b/src/pages/signin/LoginForm/index.js
index b9dfbb8dfbb5..91aba70a866f 100644
--- a/src/pages/signin/LoginForm/index.js
+++ b/src/pages/signin/LoginForm/index.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import BaseLoginForm from './BaseLoginForm';
const propTypes = {
diff --git a/src/pages/signin/LoginForm/index.native.js b/src/pages/signin/LoginForm/index.native.js
index dc55ad68e53b..87258e69165f 100644
--- a/src/pages/signin/LoginForm/index.native.js
+++ b/src/pages/signin/LoginForm/index.native.js
@@ -1,7 +1,7 @@
-import React, {useEffect, useRef} from 'react';
import PropTypes from 'prop-types';
+import React, {useEffect, useRef} from 'react';
+import AppStateMonitor from '@libs/AppStateMonitor';
import BaseLoginForm from './BaseLoginForm';
-import AppStateMonitor from '../../../libs/AppStateMonitor';
const propTypes = {
/** Function used to scroll to the top of the page */
diff --git a/src/pages/signin/SAMLSignInPage/index.js b/src/pages/signin/SAMLSignInPage/index.js
index 23ce9b93b8cc..67154c8e85fe 100644
--- a/src/pages/signin/SAMLSignInPage/index.js
+++ b/src/pages/signin/SAMLSignInPage/index.js
@@ -1,16 +1,16 @@
+import PropTypes from 'prop-types';
import React, {useEffect} from 'react';
-import {withOnyx} from 'react-native-onyx';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import ONYXKEYS from '../../../ONYXKEYS';
-import CONFIG from '../../../CONFIG';
-import Icon from '../../../components/Icon';
-import Text from '../../../components/Text';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import styles from '../../../styles/styles';
-import themeColors from '../../../styles/themes/default';
-import useLocalize from '../../../hooks/useLocalize';
+import {withOnyx} from 'react-native-onyx';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import CONFIG from '@src/CONFIG';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The credentials of the logged in person */
diff --git a/src/pages/signin/SignInHeroCopy.js b/src/pages/signin/SignInHeroCopy.js
index c2caa3ea1296..2cf3adac1022 100644
--- a/src/pages/signin/SignInHeroCopy.js
+++ b/src/pages/signin/SignInHeroCopy.js
@@ -1,13 +1,13 @@
-import {View} from 'react-native';
import PropTypes from 'prop-types';
import React from 'react';
-import Text from '../../components/Text';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import * as StyleUtils from '../../styles/StyleUtils';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
+import {View} from 'react-native';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
const propTypes = {
/** Override the green headline copy */
diff --git a/src/pages/signin/SignInHeroImage.js b/src/pages/signin/SignInHeroImage.js
index 6d53aa25e9af..8ed9a168b328 100644
--- a/src/pages/signin/SignInHeroImage.js
+++ b/src/pages/signin/SignInHeroImage.js
@@ -1,9 +1,9 @@
import React from 'react';
-import Lottie from '../../components/Lottie';
-import * as LottieAnimations from '../../components/LottieAnimations';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
+import Lottie from '@components/Lottie';
+import * as LottieAnimations from '@components/LottieAnimations';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
const propTypes = {
...windowDimensionsPropTypes,
diff --git a/src/pages/signin/SignInModal.js b/src/pages/signin/SignInModal.js
index f1ce09def084..725209537a6d 100644
--- a/src/pages/signin/SignInModal.js
+++ b/src/pages/signin/SignInModal.js
@@ -1,10 +1,10 @@
import React from 'react';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
import SignInPage from './SignInPage';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import styles from '../../styles/styles';
-import * as Session from '../../libs/actions/Session';
const propTypes = {};
diff --git a/src/pages/signin/SignInPage.js b/src/pages/signin/SignInPage.js
index 18ed29fa0415..30eadf952042 100644
--- a/src/pages/signin/SignInPage.js
+++ b/src/pages/signin/SignInPage.js
@@ -1,31 +1,31 @@
-import React, {useEffect, useRef, useState} from 'react';
+import Str from 'expensify-common/lib/str';
import PropTypes from 'prop-types';
-import _ from 'underscore';
-import {withOnyx} from 'react-native-onyx';
+import React, {useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
-import Str from 'expensify-common/lib/str';
+import {withOnyx} from 'react-native-onyx';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
-import ONYXKEYS from '../../ONYXKEYS';
-import styles from '../../styles/styles';
-import SignInPageLayout from './SignInPageLayout';
+import _ from 'underscore';
+import useLocalize from '@hooks/useLocalize';
+import useWindowDimensions from '@hooks/useWindowDimensions';
+import * as ActiveClientManager from '@libs/ActiveClientManager';
+import getPlatform from '@libs/getPlatform';
+import * as Localize from '@libs/Localize';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import Performance from '@libs/Performance';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import * as App from '@userActions/App';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import ChooseSSOOrMagicCode from './ChooseSSOOrMagicCode';
+import EmailDeliveryFailurePage from './EmailDeliveryFailurePage';
import LoginForm from './LoginForm';
-import ValidateCodeForm from './ValidateCodeForm';
-import Performance from '../../libs/Performance';
-import * as App from '../../libs/actions/App';
+import SignInPageLayout from './SignInPageLayout';
import UnlinkLoginForm from './UnlinkLoginForm';
-import EmailDeliveryFailurePage from './EmailDeliveryFailurePage';
-import * as Localize from '../../libs/Localize';
-import * as StyleUtils from '../../styles/StyleUtils';
-import useLocalize from '../../hooks/useLocalize';
-import useWindowDimensions from '../../hooks/useWindowDimensions';
-import Log from '../../libs/Log';
-import getPlatform from '../../libs/getPlatform';
-import CONST from '../../CONST';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import ChooseSSOOrMagicCode from './ChooseSSOOrMagicCode';
-import * as ActiveClientManager from '../../libs/ActiveClientManager';
-import * as Session from '../../libs/actions/Session';
+import ValidateCodeForm from './ValidateCodeForm';
const propTypes = {
/** The details about the account that the user is signing in with */
diff --git a/src/pages/signin/SignInPageHero.js b/src/pages/signin/SignInPageHero.js
index 89e9088d12f2..28cc0b711ae1 100644
--- a/src/pages/signin/SignInPageHero.js
+++ b/src/pages/signin/SignInPageHero.js
@@ -1,12 +1,12 @@
-import {View} from 'react-native';
import PropTypes from 'prop-types';
import React from 'react';
-import * as StyleUtils from '../../styles/StyleUtils';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
-import SignInHeroImage from './SignInHeroImage';
+import {View} from 'react-native';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
import SignInHeroCopy from './SignInHeroCopy';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
+import SignInHeroImage from './SignInHeroImage';
const propTypes = {
/** Override the green headline copy */
diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js
index 6ce60fc364fd..9b420753c17a 100644
--- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js
+++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.android.js
@@ -1,6 +1,6 @@
import React from 'react';
-import AndroidBackgroundImage from '../../../../../assets/images/home-background--android.svg';
-import styles from '../../../../styles/styles';
+import AndroidBackgroundImage from '@assets/images/home-background--android.svg';
+import styles from '@styles/styles';
import defaultPropTypes from './propTypes';
function BackgroundImage(props) {
diff --git a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js
index 710f7b373a81..2dc95bd28215 100644
--- a/src/pages/signin/SignInPageLayout/BackgroundImage/index.js
+++ b/src/pages/signin/SignInPageLayout/BackgroundImage/index.js
@@ -1,8 +1,8 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import MobileBackgroundImage from '../../../../../assets/images/home-background--mobile.svg';
-import DesktopBackgroundImage from '../../../../../assets/images/home-background--desktop.svg';
-import styles from '../../../../styles/styles';
+import React from 'react';
+import DesktopBackgroundImage from '@assets/images/home-background--desktop.svg';
+import MobileBackgroundImage from '@assets/images/home-background--mobile.svg';
+import styles from '@styles/styles';
import defaultPropTypes from './propTypes';
const defaultProps = {
diff --git a/src/pages/signin/SignInPageLayout/Footer.js b/src/pages/signin/SignInPageLayout/Footer.js
index 2fb5e45db760..f220dd56b613 100644
--- a/src/pages/signin/SignInPageLayout/Footer.js
+++ b/src/pages/signin/SignInPageLayout/Footer.js
@@ -1,21 +1,21 @@
-import {View} from 'react-native';
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
+import {View} from 'react-native';
import _ from 'underscore';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import themeColors from '../../../styles/themes/default';
-import variables from '../../../styles/variables';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import TextLink from '../../../components/TextLink';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import Licenses from '../Licenses';
-import Socials from '../Socials';
-import Hoverable from '../../../components/Hoverable';
-import CONST from '../../../CONST';
-import * as Session from '../../../libs/actions/Session';
-import SignInGradient from '../../../../assets/images/home-fade-gradient--mobile.svg';
+import SignInGradient from '@assets/images/home-fade-gradient--mobile.svg';
+import Hoverable from '@components/Hoverable';
+import * as Expensicons from '@components/Icon/Expensicons';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import Licenses from '@pages/signin/Licenses';
+import Socials from '@pages/signin/Socials';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import * as Session from '@userActions/Session';
+import CONST from '@src/CONST';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/signin/SignInPageLayout/SignInPageContent.js b/src/pages/signin/SignInPageLayout/SignInPageContent.js
index 571af6a640b7..14b7b7e004a6 100755
--- a/src/pages/signin/SignInPageLayout/SignInPageContent.js
+++ b/src/pages/signin/SignInPageLayout/SignInPageContent.js
@@ -1,18 +1,18 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withSafeAreaInsets} from 'react-native-safe-area-context';
-import styles from '../../../styles/styles';
-import ExpensifyWordmark from '../../../components/ExpensifyWordmark';
-import Text from '../../../components/Text';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import SignInPageForm from '../../../components/SignInPageForm';
-import compose from '../../../libs/compose';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import OfflineIndicator from '../../../components/OfflineIndicator';
-import SignInHeroImage from '../SignInHeroImage';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import variables from '../../../styles/variables';
+import ExpensifyWordmark from '@components/ExpensifyWordmark';
+import OfflineIndicator from '@components/OfflineIndicator';
+import SignInPageForm from '@components/SignInPageForm';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import SignInHeroImage from '@pages/signin/SignInHeroImage';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import variables from '@styles/variables';
const propTypes = {
/** The children to show inside the layout */
diff --git a/src/pages/signin/SignInPageLayout/index.js b/src/pages/signin/SignInPageLayout/index.js
index fdc88b6ede9e..627fdd0eaa37 100644
--- a/src/pages/signin/SignInPageLayout/index.js
+++ b/src/pages/signin/SignInPageLayout/index.js
@@ -1,21 +1,21 @@
-import React, {forwardRef, useRef, useEffect, useImperativeHandle} from 'react';
-import {View, ScrollView} from 'react-native';
-import {withSafeAreaInsets} from 'react-native-safe-area-context';
import PropTypes from 'prop-types';
-import compose from '../../../libs/compose';
-import SignInPageContent from './SignInPageContent';
+import React, {forwardRef, useEffect, useImperativeHandle, useRef} from 'react';
+import {ScrollView, View} from 'react-native';
+import {withSafeAreaInsets} from 'react-native-safe-area-context';
+import SignInGradient from '@assets/images/home-fade-gradient.svg';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import usePrevious from '@hooks/usePrevious';
+import compose from '@libs/compose';
+import SignInPageHero from '@pages/signin/SignInPageHero';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import BackgroundImage from './BackgroundImage';
import Footer from './Footer';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../../components/withWindowDimensions';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import styles from '../../../styles/styles';
-import SignInPageHero from '../SignInPageHero';
-import * as StyleUtils from '../../../styles/StyleUtils';
+import SignInPageContent from './SignInPageContent';
import scrollViewContentContainerStyles from './signInPageStyles';
-import themeColors from '../../../styles/themes/default';
-import BackgroundImage from './BackgroundImage';
-import SignInGradient from '../../../../assets/images/home-fade-gradient.svg';
-import variables from '../../../styles/variables';
-import usePrevious from '../../../hooks/usePrevious';
const propTypes = {
/** The children to show inside the layout */
@@ -185,16 +185,14 @@ SignInPageLayout.propTypes = propTypes;
SignInPageLayout.displayName = 'SignInPageLayout';
SignInPageLayout.defaultProps = defaultProps;
-export default compose(
- withWindowDimensions,
- withSafeAreaInsets,
- withLocalize,
-)(
- forwardRef((props, ref) => (
-
- )),
-);
+const SignInPageLayoutWithRef = forwardRef((props, ref) => (
+
+));
+
+SignInPageLayoutWithRef.displayName = 'SignInPageLayoutWithRef';
+
+export default compose(withWindowDimensions, withSafeAreaInsets, withLocalize)(SignInPageLayoutWithRef);
diff --git a/src/pages/signin/SignInPageLayout/signInPageStyles/index.js b/src/pages/signin/SignInPageLayout/signInPageStyles/index.js
index de3cdcc20c0c..b058c78aca86 100644
--- a/src/pages/signin/SignInPageLayout/signInPageStyles/index.js
+++ b/src/pages/signin/SignInPageLayout/signInPageStyles/index.js
@@ -1,4 +1,4 @@
-import styles from '../../../../styles/styles';
+import styles from '@styles/styles';
// On web, we can use flex to fit the content to fit the viewport within a ScrollView.
const scrollViewContentContainerStyles = styles.flex1;
diff --git a/src/pages/signin/SignInPageLayout/signInPageStyles/index.native.js b/src/pages/signin/SignInPageLayout/signInPageStyles/index.native.js
index 004534709783..76f847f638b9 100644
--- a/src/pages/signin/SignInPageLayout/signInPageStyles/index.native.js
+++ b/src/pages/signin/SignInPageLayout/signInPageStyles/index.native.js
@@ -1,4 +1,4 @@
-import styles from '../../../../styles/styles';
+import styles from '@styles/styles';
// Using flexGrow on mobile allows the ScrollView container to grow to fit the content.
// This is necessary because making the sign-in content fit exactly the viewheight causes the scroll to stop working on mobile.
diff --git a/src/pages/signin/Socials.js b/src/pages/signin/Socials.js
index f7a866d2023b..b8dddf3f799d 100644
--- a/src/pages/signin/Socials.js
+++ b/src/pages/signin/Socials.js
@@ -1,14 +1,14 @@
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
-import * as Link from '../../libs/actions/Link';
-import Icon from '../../components/Icon';
-import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import themeColors from '../../styles/themes/default';
-import styles from '../../styles/styles';
-import variables from '../../styles/variables';
-import CONST from '../../CONST';
+import Icon from '@components/Icon';
+import * as Expensicons from '@components/Icon/Expensicons';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import variables from '@styles/variables';
+import * as Link from '@userActions/Link';
+import CONST from '@src/CONST';
const socialsList = [
{
diff --git a/src/pages/signin/Terms.js b/src/pages/signin/Terms.js
index 15f7c17a2889..13af9829305d 100644
--- a/src/pages/signin/Terms.js
+++ b/src/pages/signin/Terms.js
@@ -1,9 +1,9 @@
import React from 'react';
-import styles from '../../styles/styles';
-import CONST from '../../CONST';
-import Text from '../../components/Text';
-import TextLink from '../../components/TextLink';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
const linkStyles = [styles.textExtraSmallSupporting, styles.link];
diff --git a/src/pages/signin/ThirdPartySignInPage.js b/src/pages/signin/ThirdPartySignInPage.js
index fa6aa4d5895e..c480356d5c15 100644
--- a/src/pages/signin/ThirdPartySignInPage.js
+++ b/src/pages/signin/ThirdPartySignInPage.js
@@ -1,21 +1,21 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {ActivityIndicator, View} from 'react-native';
-import {SafeAreaView} from 'react-native-safe-area-context';
import {withOnyx} from 'react-native-onyx';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
+import {SafeAreaView} from 'react-native-safe-area-context';
+import AppleSignIn from '@components/SignInButtons/AppleSignIn';
+import GoogleSignIn from '@components/SignInButtons/GoogleSignIn';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import SignInPageLayout from './SignInPageLayout';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import Text from '../../components/Text';
-import TextLink from '../../components/TextLink';
-import AppleSignIn from '../../components/SignInButtons/AppleSignIn';
-import GoogleSignIn from '../../components/SignInButtons/GoogleSignIn';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
-import ROUTES from '../../ROUTES';
-import Navigation from '../../libs/Navigation/Navigation';
-import CONST from '../../CONST';
-import ONYXKEYS from '../../ONYXKEYS';
const propTypes = {
/** Which sign in provider we are using. */
diff --git a/src/pages/signin/UnlinkLoginForm.js b/src/pages/signin/UnlinkLoginForm.js
index 6807ba74c6f9..d0fc44c1b1f7 100644
--- a/src/pages/signin/UnlinkLoginForm.js
+++ b/src/pages/signin/UnlinkLoginForm.js
@@ -1,22 +1,22 @@
+import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
import React from 'react';
-import _ from 'underscore';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import Str from 'expensify-common/lib/str';
-import styles from '../../styles/styles';
-import Button from '../../components/Button';
-import Text from '../../components/Text';
-import * as Session from '../../libs/actions/Session';
-import ONYXKEYS from '../../ONYXKEYS';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import redirectToSignIn from '../../libs/actions/SignInRedirect';
-import networkPropTypes from '../../components/networkPropTypes';
-import {withNetwork} from '../../components/OnyxProvider';
-import DotIndicatorMessage from '../../components/DotIndicatorMessage';
-import CONST from '../../CONST';
-import PressableWithFeedback from '../../components/Pressable/PressableWithFeedback';
+import _ from 'underscore';
+import Button from '@components/Button';
+import DotIndicatorMessage from '@components/DotIndicatorMessage';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import styles from '@styles/styles';
+import * as Session from '@userActions/Session';
+import redirectToSignIn from '@userActions/SignInRedirect';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js
index dc100fffe4f1..2d8f0e98e03c 100755
--- a/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js
+++ b/src/pages/signin/ValidateCodeForm/BaseValidateCodeForm.js
@@ -1,32 +1,32 @@
-import React, {useState, useEffect, useRef, useCallback} from 'react';
-import {View} from 'react-native';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useRef, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import styles from '../../../styles/styles';
-import Button from '../../../components/Button';
-import Text from '../../../components/Text';
-import themeColors from '../../../styles/themes/default';
-import * as Session from '../../../libs/actions/Session';
-import ONYXKEYS from '../../../ONYXKEYS';
-import CONST from '../../../CONST';
-import ChangeExpensifyLoginLink from '../ChangeExpensifyLoginLink';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import compose from '../../../libs/compose';
-import * as ValidationUtils from '../../../libs/ValidationUtils';
-import canFocusInputOnScreenFocus from '../../../libs/canFocusInputOnScreenFocus';
-import * as ErrorUtils from '../../../libs/ErrorUtils';
-import {withNetwork} from '../../../components/OnyxProvider';
-import networkPropTypes from '../../../components/networkPropTypes';
-import * as User from '../../../libs/actions/User';
-import FormHelpMessage from '../../../components/FormHelpMessage';
-import MagicCodeInput from '../../../components/MagicCodeInput';
-import Terms from '../Terms';
-import PressableWithFeedback from '../../../components/Pressable/PressableWithFeedback';
-import usePrevious from '../../../hooks/usePrevious';
-import * as StyleUtils from '../../../styles/StyleUtils';
-import TextInput from '../../../components/TextInput';
+import Button from '@components/Button';
+import FormHelpMessage from '@components/FormHelpMessage';
+import MagicCodeInput from '@components/MagicCodeInput';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import PressableWithFeedback from '@components/Pressable/PressableWithFeedback';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import usePrevious from '@hooks/usePrevious';
+import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import ChangeExpensifyLoginLink from '@pages/signin/ChangeExpensifyLoginLink';
+import Terms from '@pages/signin/Terms';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import * as Session from '@userActions/Session';
+import * as User from '@userActions/User';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/signin/ValidateCodeForm/index.android.js b/src/pages/signin/ValidateCodeForm/index.android.js
index 1e888d24bc60..9adddf7c92d8 100644
--- a/src/pages/signin/ValidateCodeForm/index.android.js
+++ b/src/pages/signin/ValidateCodeForm/index.android.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import BaseValidateCodeForm from './BaseValidateCodeForm';
const defaultProps = {};
diff --git a/src/pages/signin/ValidateCodeForm/index.js b/src/pages/signin/ValidateCodeForm/index.js
index 540b6a3e3ed6..35afc283972b 100644
--- a/src/pages/signin/ValidateCodeForm/index.js
+++ b/src/pages/signin/ValidateCodeForm/index.js
@@ -1,5 +1,5 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import BaseValidateCodeForm from './BaseValidateCodeForm';
const defaultProps = {};
diff --git a/src/pages/tasks/NewTaskDescriptionPage.js b/src/pages/tasks/NewTaskDescriptionPage.js
index 378adf6a9a41..4d1276b1fffc 100644
--- a/src/pages/tasks/NewTaskDescriptionPage.js
+++ b/src/pages/tasks/NewTaskDescriptionPage.js
@@ -1,24 +1,24 @@
-import React, {useRef, useCallback} from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import {useFocusEffect} from '@react-navigation/native';
-import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import TextInput from '../../components/TextInput';
-import Permissions from '../../libs/Permissions';
-import ROUTES from '../../ROUTES';
-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';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useAutoFocusInput from '@hooks/useAutoFocusInput';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import updateMultilineInputRange from '@libs/UpdateMultilineInputRange';
+import styles from '@styles/styles';
+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 */
@@ -41,26 +41,7 @@ const defaultProps = {
};
function NewTaskDescriptionPage(props) {
- const inputRef = useRef(null);
- const focusTimeoutRef = useRef(null);
- // On submit, we want to call the assignTask function and wait to validate
- // the response
-
- useFocusEffect(
- useCallback(() => {
- focusTimeoutRef.current = setTimeout(() => {
- if (inputRef.current) {
- inputRef.current.focus();
- }
- return () => {
- if (!focusTimeoutRef.current) {
- return;
- }
- clearTimeout(focusTimeoutRef.current);
- };
- }, CONST.ANIMATED_TRANSITION);
- }, []),
- );
+ const {inputCallbackRef} = useAutoFocusInput();
const onSubmit = (values) => {
Task.setDescriptionValue(values.taskDescription);
@@ -91,7 +72,7 @@ function NewTaskDescriptionPage(props) {
enabledWhenOffline
>
- {
- if (!el) {
- return;
- }
- inputRef.current = el;
- updateMultilineInputRange(inputRef.current);
+ inputCallbackRef(el);
+ updateMultilineInputRange(el);
}}
autoGrowHeight
submitOnEnter={!Browser.isMobile()}
diff --git a/src/pages/tasks/NewTaskDetailsPage.js b/src/pages/tasks/NewTaskDetailsPage.js
index 668a61526198..0ab3771c28f2 100644
--- a/src/pages/tasks/NewTaskDetailsPage.js
+++ b/src/pages/tasks/NewTaskDetailsPage.js
@@ -1,23 +1,24 @@
+import PropTypes from 'prop-types';
import React, {useEffect, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-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 * as Browser from '../../libs/Browser';
-import useAutoFocusInput from '../../hooks/useAutoFocusInput';
+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 withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useAutoFocusInput from '@hooks/useAutoFocusInput';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Beta features list */
@@ -86,7 +87,7 @@ function NewTaskDetailsPage(props) {
shouldShowBackButton
onBackButtonPress={() => Task.dismissModalAndClearOutTaskInfo()}
/>
-
+
);
}
diff --git a/src/pages/tasks/NewTaskPage.js b/src/pages/tasks/NewTaskPage.js
index 790bd6ceeb64..41cda42ccbd8 100644
--- a/src/pages/tasks/NewTaskPage.js
+++ b/src/pages/tasks/NewTaskPage.js
@@ -1,26 +1,27 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useEffect, useMemo, useState} from 'react';
import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import Permissions from '../../libs/Permissions';
-import ROUTES from '../../ROUTES';
-import MenuItemWithTopDescription from '../../components/MenuItemWithTopDescription';
-import MenuItem from '../../components/MenuItem';
-import reportPropTypes from '../reportPropTypes';
-import * as Task from '../../libs/actions/Task';
-import * as ReportUtils from '../../libs/ReportUtils';
-import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import * as LocalePhoneNumber from '../../libs/LocalePhoneNumber';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItem from '@components/MenuItem';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import * as LocalePhoneNumber from '@libs/LocalePhoneNumber';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import Permissions from '@libs/Permissions';
+import * as ReportUtils from '@libs/ReportUtils';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Task Creation Data */
@@ -64,6 +65,7 @@ const defaultProps = {
function NewTaskPage(props) {
const [assignee, setAssignee] = useState({});
+ const assigneeTooltipDetails = ReportUtils.getDisplayNamesWithTooltips(OptionsListUtils.getPersonalDetailsForAccountIDs([props.task.assigneeAccountID], props.personalDetails), false);
const [shareDestination, setShareDestination] = useState({});
const [title, setTitle] = useState('');
const [description, setDescription] = useState('');
@@ -185,6 +187,7 @@ function NewTaskPage(props) {
icon={assignee.icons}
onPress={() => Navigation.navigate(ROUTES.NEW_TASK_ASSIGNEE)}
shouldShowRightIcon
+ titleWithTooltips={assigneeTooltipDetails}
/>
Navigation.navigate(ROUTES.NEW_TASK_SHARE_DESTINATION)}
interactive={!props.task.parentReportID}
shouldShowRightIcon={!props.task.parentReportID}
+ titleWithTooltips={!shareDestination.shouldUseFullTitleToDisplay && shareDestination.displayNamesWithTooltips}
/>
diff --git a/src/pages/tasks/NewTaskTitlePage.js b/src/pages/tasks/NewTaskTitlePage.js
index 62eb1da4872a..8508024b45ef 100644
--- a/src/pages/tasks/NewTaskTitlePage.js
+++ b/src/pages/tasks/NewTaskTitlePage.js
@@ -1,21 +1,22 @@
-import React, {useRef} from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-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 Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import useAutoFocusInput from '@hooks/useAutoFocusInput';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import Permissions from '@libs/Permissions';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Beta features list */
@@ -38,7 +39,7 @@ const defaultProps = {
};
function NewTaskTitlePage(props) {
- const inputRef = useRef(null);
+ const {inputCallbackRef} = useAutoFocusInput();
/**
* @param {Object} values - form input values passed by the Form component
@@ -68,13 +69,6 @@ function NewTaskTitlePage(props) {
}
return (
{
- if (!inputRef.current) {
- return;
- }
-
- inputRef.current.focus();
- }}
includeSafeAreaPaddingBottom={false}
shouldEnableMaxHeight
testID={NewTaskTitlePage.displayName}
@@ -97,7 +91,7 @@ function NewTaskTitlePage(props) {
(inputRef.current = el)}
+ ref={inputCallbackRef}
inputID="taskTitle"
label={props.translate('task.title')}
accessibilityLabel={props.translate('task.title')}
diff --git a/src/pages/tasks/TaskAssigneeSelectorModal.js b/src/pages/tasks/TaskAssigneeSelectorModal.js
index bfa3ac884e4a..cb08d2928d88 100644
--- a/src/pages/tasks/TaskAssigneeSelectorModal.js
+++ b/src/pages/tasks/TaskAssigneeSelectorModal.js
@@ -1,27 +1,27 @@
/* eslint-disable es/no-optional-chaining */
-import React, {useState, useEffect, useMemo, useCallback, useRef} from 'react';
-import {View} from 'react-native';
import lodashGet from 'lodash/get';
-import _ from 'underscore';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import OptionsSelector from '../../components/OptionsSelector';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import ONYXKEYS from '../../ONYXKEYS';
-import styles from '../../styles/styles';
-import Navigation from '../../libs/Navigation/Navigation';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import CONST from '../../CONST';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import personalDetailsPropType from '../personalDetailsPropType';
-import reportPropTypes from '../reportPropTypes';
-import * as ReportUtils from '../../libs/ReportUtils';
-import ROUTES from '../../ROUTES';
-import * as Task from '../../libs/actions/Task';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import withCurrentUserPersonalDetails from '../../components/withCurrentUserPersonalDetails';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import OptionsSelector from '@components/OptionsSelector';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Beta features list */
diff --git a/src/pages/tasks/TaskDescriptionPage.js b/src/pages/tasks/TaskDescriptionPage.js
index 01ed7e55f8a0..5d496fbca6c1 100644
--- a/src/pages/tasks/TaskDescriptionPage.js
+++ b/src/pages/tasks/TaskDescriptionPage.js
@@ -1,33 +1,28 @@
+import {useFocusEffect} from '@react-navigation/native';
import React, {useCallback, useRef} from 'react';
-import PropTypes from 'prop-types';
import {View} from 'react-native';
-import {useFocusEffect} from '@react-navigation/native';
import {withOnyx} from 'react-native-onyx';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import Form from '../../components/Form';
-import ONYXKEYS from '../../ONYXKEYS';
-import TextInput from '../../components/TextInput';
-import reportPropTypes from '../reportPropTypes';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import * as Task from '../../libs/actions/Task';
-import * as ReportUtils from '../../libs/ReportUtils';
-import CONST from '../../CONST';
-import updateMultilineInputRange from '../../libs/UpdateMultilineInputRange';
-import * as Browser from '../../libs/Browser';
-import Navigation from '../../libs/Navigation/Navigation';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import withCurrentUserPersonalDetails from '../../components/withCurrentUserPersonalDetails';
-import withReportOrNotFound from '../home/report/withReportOrNotFound';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+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 withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import updateMultilineInputRange from '@libs/UpdateMultilineInputRange';
+import withReportOrNotFound from '@pages/home/report/withReportOrNotFound';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
- /** Current user session */
- session: PropTypes.shape({
- email: PropTypes.string.isRequired,
- }),
-
/** The report currently being looked at */
report: reportPropTypes,
@@ -36,7 +31,6 @@ const propTypes = {
};
const defaultProps = {
- session: {},
report: {},
};
@@ -47,7 +41,7 @@ function TaskDescriptionPage(props) {
(values) => {
// Set the description of the report in the store and then call Task.editTaskReport
// to update the description of the report on the server
- Task.editTaskAndNavigate(props.report, props.session.accountID, {description: values.description});
+ Task.editTaskAndNavigate(props.report, {description: values.description});
},
[props],
);
@@ -88,7 +82,7 @@ function TaskDescriptionPage(props) {
>
-
+
);
@@ -132,9 +127,6 @@ export default compose(
withCurrentUserPersonalDetails,
withReportOrNotFound(),
withOnyx({
- session: {
- key: ONYXKEYS.SESSION,
- },
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
},
diff --git a/src/pages/tasks/TaskShareDestinationSelectorModal.js b/src/pages/tasks/TaskShareDestinationSelectorModal.js
index 2fc8f0eab014..fde02c2a4108 100644
--- a/src/pages/tasks/TaskShareDestinationSelectorModal.js
+++ b/src/pages/tasks/TaskShareDestinationSelectorModal.js
@@ -1,24 +1,24 @@
/* eslint-disable es/no-optional-chaining */
-import React, {useState, useEffect, useMemo, useCallback, useRef} from 'react';
-import _ from 'underscore';
-import {View} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import OptionsSelector from '../../components/OptionsSelector';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import ONYXKEYS from '../../ONYXKEYS';
-import styles from '../../styles/styles';
-import Navigation from '../../libs/Navigation/Navigation';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import CONST from '../../CONST';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import personalDetailsPropType from '../personalDetailsPropType';
-import reportPropTypes from '../reportPropTypes';
-import * as Task from '../../libs/actions/Task';
-import * as ReportUtils from '../../libs/ReportUtils';
-import ROUTES from '../../ROUTES';
+import _ from 'underscore';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import OptionsSelector from '@components/OptionsSelector';
+import ScreenWrapper from '@components/ScreenWrapper';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/* Onyx Props */
diff --git a/src/pages/tasks/TaskTitlePage.js b/src/pages/tasks/TaskTitlePage.js
index 32cd6c3d2cc3..375a23cc3012 100644
--- a/src/pages/tasks/TaskTitlePage.js
+++ b/src/pages/tasks/TaskTitlePage.js
@@ -1,40 +1,34 @@
-import _ from 'underscore';
import React, {useCallback, useRef} from 'react';
-import PropTypes from 'prop-types';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import Form from '../../components/Form';
-import ONYXKEYS from '../../ONYXKEYS';
-import TextInput from '../../components/TextInput';
-import styles from '../../styles/styles';
-import reportPropTypes from '../reportPropTypes';
-import compose from '../../libs/compose';
-import * as Task from '../../libs/actions/Task';
-import * as ReportUtils from '../../libs/ReportUtils';
-import CONST from '../../CONST';
-import Navigation from '../../libs/Navigation/Navigation';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import withCurrentUserPersonalDetails from '../../components/withCurrentUserPersonalDetails';
-import withReportOrNotFound from '../home/report/withReportOrNotFound';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+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 withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import withReportOrNotFound from '@pages/home/report/withReportOrNotFound';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as Task from '@userActions/Task';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The report currently being looked at */
report: reportPropTypes,
- /** Current user session */
- session: PropTypes.shape({
- email: PropTypes.string.isRequired,
- }),
-
/* Onyx Props */
...withLocalizePropTypes,
};
const defaultProps = {
- session: {},
report: {},
};
@@ -58,7 +52,7 @@ function TaskTitlePage(props) {
(values) => {
// Set the title of the report in the store and then call Task.editTaskReport
// to update the title of the report on the server
- Task.editTaskAndNavigate(props.report, props.session.accountID, {title: values.title});
+ Task.editTaskAndNavigate(props.report, {title: values.title});
},
[props],
);
@@ -84,7 +78,7 @@ function TaskTitlePage(props) {
{({didScreenTransitionEnd}) => (
-
+
)}
@@ -127,9 +122,6 @@ export default compose(
withCurrentUserPersonalDetails,
withReportOrNotFound(),
withOnyx({
- session: {
- key: ONYXKEYS.SESSION,
- },
report: {
key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${route.params.reportID}`,
},
diff --git a/src/pages/wallet/WalletStatementPage.js b/src/pages/wallet/WalletStatementPage.js
index b220776cd9ef..0d33be70f1b7 100644
--- a/src/pages/wallet/WalletStatementPage.js
+++ b/src/pages/wallet/WalletStatementPage.js
@@ -1,25 +1,25 @@
-import React, {useEffect} from 'react';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
-import {withOnyx} from 'react-native-onyx';
import {format, getMonth, getYear} from 'date-fns';
import Str from 'expensify-common/lib/str';
-import Navigation from '../../libs/Navigation/Navigation';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import ONYXKEYS from '../../ONYXKEYS';
-import compose from '../../libs/compose';
-import CONFIG from '../../CONFIG';
-import WalletStatementModal from '../../components/WalletStatementModal';
-import * as User from '../../libs/actions/User';
-import fileDownload from '../../libs/fileDownload';
-import Growl from '../../libs/Growl';
-import CONST from '../../CONST';
-import FullPageOfflineBlockingView from '../../components/BlockingViews/FullPageOfflineBlockingView';
-import {withNetwork} from '../../components/OnyxProvider';
-import networkPropTypes from '../../components/networkPropTypes';
-import DateUtils from '../../libs/DateUtils';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import FullPageOfflineBlockingView from '@components/BlockingViews/FullPageOfflineBlockingView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import ScreenWrapper from '@components/ScreenWrapper';
+import WalletStatementModal from '@components/WalletStatementModal';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import DateUtils from '@libs/DateUtils';
+import fileDownload from '@libs/fileDownload';
+import Growl from '@libs/Growl';
+import Navigation from '@libs/Navigation/Navigation';
+import * as User from '@userActions/User';
+import CONFIG from '@src/CONFIG';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The route object passed to this page from the navigator */
diff --git a/src/pages/workspace/WorkspaceInitialPage.js b/src/pages/workspace/WorkspaceInitialPage.js
index d275b7f0dd10..207db2620f9f 100644
--- a/src/pages/workspace/WorkspaceInitialPage.js
+++ b/src/pages/workspace/WorkspaceInitialPage.js
@@ -1,37 +1,39 @@
-import _ from 'underscore';
import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback, useEffect, useState} from 'react';
-import {View, ScrollView} from 'react-native';
+import {ScrollView, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import styles from '../../styles/styles';
-import Tooltip from '../../components/Tooltip';
-import Text from '../../components/Text';
-import ConfirmModal from '../../components/ConfirmModal';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import * as App from '../../libs/actions/App';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import MenuItem from '../../components/MenuItem';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import compose from '../../libs/compose';
-import Avatar from '../../components/Avatar';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import {policyPropTypes, policyDefaultProps} from './withPolicy';
+import _ from 'underscore';
+import Avatar from '@components/Avatar';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import ConfirmModal from '@components/ConfirmModal';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import Tooltip from '@components/Tooltip';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions from '@components/withWindowDimensions';
+import useSingleExecution from '@hooks/useSingleExecution';
+import useWaitForNavigation from '@hooks/useWaitForNavigation';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import reportPropTypes from '@pages/reportPropTypes';
+import styles from '@styles/styles';
+import * as App from '@userActions/App';
+import * as Policy from '@userActions/Policy';
+import * as ReimbursementAccount from '@userActions/ReimbursementAccount';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {policyDefaultProps, policyPropTypes} from './withPolicy';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
-import reportPropTypes from '../reportPropTypes';
-import * as Policy from '../../libs/actions/Policy';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import CONST from '../../CONST';
-import * as ReimbursementAccount from '../../libs/actions/ReimbursementAccount';
-import ONYXKEYS from '../../ONYXKEYS';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
-import * as ReimbursementAccountProps from '../ReimbursementAccount/reimbursementAccountPropTypes';
-import * as ReportUtils from '../../libs/ReportUtils';
-import withWindowDimensions from '../../components/withWindowDimensions';
-import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback';
const propTypes = {
...policyPropTypes,
@@ -70,6 +72,8 @@ function WorkspaceInitialPage(props) {
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isCurrencyModalOpen, setIsCurrencyModalOpen] = useState(false);
const hasPolicyCreationError = Boolean(policy.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD && policy.errors);
+ const waitForNavigate = useWaitForNavigation();
+ const {singleExecution, isExecuting} = useSingleExecution();
/**
* Call the delete policy and hide the modal
@@ -88,7 +92,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
}, []);
@@ -129,39 +133,39 @@ function WorkspaceInitialPage(props) {
{
translationKey: 'workspace.common.settings',
icon: Expensicons.Gear,
- action: () => Navigation.navigate(ROUTES.WORKSPACE_SETTINGS.getRoute(policy.id)),
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_SETTINGS.getRoute(policy.id)))),
brickRoadIndicator: hasGeneralSettingsError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '',
},
{
translationKey: 'workspace.common.card',
icon: Expensicons.ExpensifyCard,
- action: () => Navigation.navigate(ROUTES.WORKSPACE_CARD.getRoute(policy.id)),
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_CARD.getRoute(policy.id)))),
},
{
translationKey: 'workspace.common.reimburse',
icon: Expensicons.Receipt,
- action: () => Navigation.navigate(ROUTES.WORKSPACE_REIMBURSE.getRoute(policy.id)),
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_REIMBURSE.getRoute(policy.id)))),
error: hasCustomUnitsError,
},
{
translationKey: 'workspace.common.bills',
icon: Expensicons.Bill,
- action: () => Navigation.navigate(ROUTES.WORKSPACE_BILLS.getRoute(policy.id)),
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_BILLS.getRoute(policy.id)))),
},
{
translationKey: 'workspace.common.invoices',
icon: Expensicons.Invoice,
- action: () => Navigation.navigate(ROUTES.WORKSPACE_INVOICES.getRoute(policy.id)),
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_INVOICES.getRoute(policy.id)))),
},
{
translationKey: 'workspace.common.travel',
icon: Expensicons.Luggage,
- action: () => Navigation.navigate(ROUTES.WORKSPACE_TRAVEL.getRoute(policy.id)),
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_TRAVEL.getRoute(policy.id)))),
},
{
translationKey: 'workspace.common.members',
icon: Expensicons.Users,
- action: () => Navigation.navigate(ROUTES.WORKSPACE_MEMBERS.getRoute(policy.id)),
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_MEMBERS.getRoute(policy.id)))),
brickRoadIndicator: hasMembersError ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '',
},
{
@@ -169,7 +173,7 @@ function WorkspaceInitialPage(props) {
icon: Expensicons.Bank,
action: () =>
policy.outputCurrency === CONST.CURRENCY.USD
- ? ReimbursementAccount.navigateToBankAccountRoute(policy.id, Navigation.getActiveRoute().replace(/\?.*/, ''))
+ ? singleExecution(waitForNavigate(() => ReimbursementAccount.navigateToBankAccountRoute(policy.id, Navigation.getActiveRoute().replace(/\?.*/, ''))))()
: setIsCurrencyModalOpen(true),
brickRoadIndicator: !_.isEmpty(props.reimbursementAccount.errors) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : '',
},
@@ -208,6 +212,9 @@ function WorkspaceInitialPage(props) {
title={props.translate('workspace.common.workspace')}
shouldShowThreeDotsButton
shouldShowGetAssistanceButton
+ singleExecution={singleExecution}
+ shouldDisableGetAssistanceButton={isExecuting}
+ shouldDisableThreeDotsButton={isExecuting}
guidesCallTaskID={CONST.GUIDES_CALL_TASK_IDS.WORKSPACE_INITIAL}
threeDotsMenuItems={threeDotsMenuItems}
threeDotsAnchorPosition={styles.threeDotsPopoverOffset(props.windowWidth)}
@@ -225,9 +232,9 @@ function WorkspaceInitialPage(props) {
openEditor(policy.id)}
+ onPress={singleExecution(waitForNavigate(() => openEditor(policy.id)))}
accessibilityLabel={props.translate('workspace.common.settings')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
@@ -245,9 +252,9 @@ function WorkspaceInitialPage(props) {
{!_.isEmpty(policy.name) && (
openEditor(policy.id)}
+ onPress={singleExecution(waitForNavigate(() => openEditor(policy.id)))}
accessibilityLabel={props.translate('workspace.common.settings')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
>
@@ -262,15 +269,19 @@ function WorkspaceInitialPage(props) {
)}
+ {/*
+ Ideally we should use MenuList component for MenuItems with singleExecution/Navigation actions.
+ In this case where user can click on workspace avatar or menu items, we need to have a check for `isExecuting`. So, we are directly mapping menuItems.
+ */}
{_.map(menuItems, (item) => (
item.action()}
+ onPress={item.action}
shouldShowRightIcon
brickRoadIndicator={item.brickRoadIndicator}
/>
diff --git a/src/pages/workspace/WorkspaceInviteMessagePage.js b/src/pages/workspace/WorkspaceInviteMessagePage.js
index 5e7efadd3778..1414354b4b38 100644
--- a/src/pages/workspace/WorkspaceInviteMessagePage.js
+++ b/src/pages/workspace/WorkspaceInviteMessagePage.js
@@ -1,32 +1,32 @@
-import React from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
-import {View, Keyboard} from 'react-native';
+import React from 'react';
+import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as Policy from '../../libs/actions/Policy';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import TextInput from '../../components/TextInput';
-import MultipleAvatars from '../../components/MultipleAvatars';
-import CONST from '../../CONST';
-import * as Link from '../../libs/actions/Link';
-import Text from '../../components/Text';
-import {policyPropTypes, policyDefaultProps} from './withPolicy';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import Form from '@components/Form';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MultipleAvatars from '@components/MultipleAvatars';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withNavigationFocus from '@components/withNavigationFocus';
+import compose from '@libs/compose';
+import * as Localize from '@libs/Localize';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import {policyDefaultProps, policyPropTypes} from './withPolicy';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import ROUTES from '../../ROUTES';
-import * as Localize from '../../libs/Localize';
-import Form from '../../components/Form';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import withNavigationFocus from '../../components/withNavigationFocus';
-import PressableWithoutFeedback from '../../components/Pressable/PressableWithoutFeedback';
const personalDetailsPropTypes = PropTypes.shape({
/** The accountID of the person */
@@ -239,6 +239,7 @@ class WorkspaceInviteMessagePage extends React.Component {
WorkspaceInviteMessagePage.propTypes = propTypes;
WorkspaceInviteMessagePage.defaultProps = defaultProps;
+WorkspaceInviteMessagePage.displayName = 'WorkspaceInviteMessagePage';
export default compose(
withLocalize,
diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js
index a21173dd7d98..afb0c55e7d4e 100644
--- a/src/pages/workspace/WorkspaceInvitePage.js
+++ b/src/pages/workspace/WorkspaceInvitePage.js
@@ -1,27 +1,27 @@
-import React, {useEffect, useMemo, useState} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useEffect, useMemo, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as Policy from '../../libs/actions/Policy';
-import FormAlertWithSubmitButton from '../../components/FormAlertWithSubmitButton';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import CONST from '../../CONST';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import styles from '@styles/styles';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import {policyDefaultProps, policyPropTypes} from './withPolicy';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import ROUTES from '../../ROUTES';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import * as Browser from '../../libs/Browser';
-import useNetwork from '../../hooks/useNetwork';
-import useLocalize from '../../hooks/useLocalize';
-import SelectionList from '../../components/SelectionList';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
const personalDetailsPropTypes = PropTypes.shape({
diff --git a/src/pages/workspace/WorkspaceMembersPage.js b/src/pages/workspace/WorkspaceMembersPage.js
index 859064444b2c..3ee24b2db1b3 100644
--- a/src/pages/workspace/WorkspaceMembersPage.js
+++ b/src/pages/workspace/WorkspaceMembersPage.js
@@ -1,37 +1,38 @@
-import React, {useCallback, useEffect, useState, useMemo, useRef} from 'react';
-import _ from 'underscore';
import lodashGet from 'lodash/get';
-import {InteractionManager, View} from 'react-native';
import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
+import {InteractionManager, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import styles from '../../styles/styles';
-import ONYXKEYS from '../../ONYXKEYS';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import Navigation from '../../libs/Navigation/Navigation';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize';
-import compose from '../../libs/compose';
-import * as Policy from '../../libs/actions/Policy';
-import * as OptionsListUtils from '../../libs/OptionsListUtils';
-import Button from '../../components/Button';
-import ROUTES from '../../ROUTES';
-import ConfirmModal from '../../components/ConfirmModal';
-import personalDetailsPropType from '../personalDetailsPropType';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import Button from '@components/Button';
+import ConfirmModal from '@components/ConfirmModal';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MessagesRow from '@components/MessagesRow';
+import networkPropTypes from '@components/networkPropTypes';
+import {withNetwork} from '@components/OnyxProvider';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import Text from '@components/Text';
+import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '@components/withCurrentUserPersonalDetails';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import usePrevious from '@hooks/usePrevious';
+import * as Browser from '@libs/Browser';
+import compose from '@libs/compose';
+import Log from '@libs/Log';
+import Navigation from '@libs/Navigation/Navigation';
+import * as OptionsListUtils from '@libs/OptionsListUtils';
+import * as PersonalDetailsUtils from '@libs/PersonalDetailsUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as UserUtils from '@libs/UserUtils';
+import personalDetailsPropType from '@pages/personalDetailsPropType';
+import styles from '@styles/styles';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import {policyDefaultProps, policyPropTypes} from './withPolicy';
-import CONST from '../../CONST';
-import {withNetwork} from '../../components/OnyxProvider';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import networkPropTypes from '../../components/networkPropTypes';
-import * as UserUtils from '../../libs/UserUtils';
-import withCurrentUserPersonalDetails, {withCurrentUserPersonalDetailsDefaultProps, withCurrentUserPersonalDetailsPropTypes} from '../../components/withCurrentUserPersonalDetails';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import usePrevious from '../../hooks/usePrevious';
-import Log from '../../libs/Log';
-import * as PersonalDetailsUtils from '../../libs/PersonalDetailsUtils';
-import SelectionList from '../../components/SelectionList';
-import Text from '../../components/Text';
-import * as Browser from '../../libs/Browser';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
const propTypes = {
@@ -290,6 +291,7 @@ function WorkspaceMembersPage(props) {
const currentUserLogin = lodashGet(props.currentUserPersonalDetails, 'login');
const policyID = lodashGet(props.route, 'params.policyID');
const policyName = lodashGet(props.policy, 'name');
+ const invitedPrimaryToSecondaryLogins = _.invert(props.policy.primaryLoginsInvited);
const getMemberOptions = () => {
let result = [];
@@ -361,12 +363,15 @@ function WorkspaceMembersPage(props) {
icons: [
{
source: UserUtils.getAvatar(details.avatar, accountID),
- name: details.login,
+ name: props.formatPhoneNumber(details.login),
type: CONST.ICON_TYPE_AVATAR,
},
],
errors: policyMember.errors,
pendingAction: policyMember.pendingAction,
+
+ // Note which secondary login was used to invite this primary login
+ invitedSecondaryLogin: invitedPrimaryToSecondaryLogins[details.login] || '',
});
});
@@ -383,6 +388,20 @@ function WorkspaceMembersPage(props) {
return searchValue.trim() && !data.length ? props.translate('workspace.common.memberNotFound') : '';
};
+ const getHeaderContent = () => {
+ if (_.isEmpty(invitedPrimaryToSecondaryLogins)) {
+ return null;
+ }
+ return (
+ Policy.dismissAddedWithPrimaryMessages(policyID)}
+ />
+ );
+ };
+
return (
toggleUser(item.accountID)}
onSelectAll={() => toggleAllUsers(data)}
onDismissError={dismissError}
diff --git a/src/pages/workspace/WorkspaceNewRoomPage.js b/src/pages/workspace/WorkspaceNewRoomPage.js
index 80c1a13731bd..4ac16188a652 100644
--- a/src/pages/workspace/WorkspaceNewRoomPage.js
+++ b/src/pages/workspace/WorkspaceNewRoomPage.js
@@ -1,32 +1,32 @@
-import React, {useState, useEffect, useCallback, useMemo, useRef} from 'react';
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View} from 'react-native';
-import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import withNavigationFocus from '../../components/withNavigationFocus';
-import * as Report from '../../libs/actions/Report';
-import * as App from '../../libs/actions/App';
-import useLocalize from '../../hooks/useLocalize';
-import styles from '../../styles/styles';
-import RoomNameInput from '../../components/RoomNameInput';
-import KeyboardAvoidingView from '../../components/KeyboardAvoidingView';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import Text from '../../components/Text';
-import TextInput from '../../components/TextInput';
-import Permissions from '../../libs/Permissions';
-import * as ErrorUtils from '../../libs/ErrorUtils';
-import * as ValidationUtils from '../../libs/ValidationUtils';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import Form from '../../components/Form';
-import policyMemberPropType from '../policyMemberPropType';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import compose from '../../libs/compose';
-import variables from '../../styles/variables';
-import useDelayedInputFocus from '../../hooks/useDelayedInputFocus';
-import ValuePicker from '../../components/ValuePicker';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import Form from '@components/Form';
+import KeyboardAvoidingView from '@components/KeyboardAvoidingView';
+import RoomNameInput from '@components/RoomNameInput';
+import ScreenWrapper from '@components/ScreenWrapper';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import ValuePicker from '@components/ValuePicker';
+import withNavigationFocus from '@components/withNavigationFocus';
+import useDelayedInputFocus from '@hooks/useDelayedInputFocus';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import * as ErrorUtils from '@libs/ErrorUtils';
+import Permissions from '@libs/Permissions';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as ValidationUtils from '@libs/ValidationUtils';
+import policyMemberPropType from '@pages/policyMemberPropType';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
+import * as App from '@userActions/App';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** All reports shared with the user */
@@ -166,7 +166,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()}
>
diff --git a/src/pages/workspace/WorkspacePageWithSections.js b/src/pages/workspace/WorkspacePageWithSections.js
index fbe950248062..98e9da3674c1 100644
--- a/src/pages/workspace/WorkspacePageWithSections.js
+++ b/src/pages/workspace/WorkspacePageWithSections.js
@@ -1,25 +1,25 @@
-import React, {useEffect} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useEffect} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import styles from '../../styles/styles';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import Navigation from '../../libs/Navigation/Navigation';
-import compose from '../../libs/compose';
-import ROUTES from '../../ROUTES';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import ONYXKEYS from '../../ONYXKEYS';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import BankAccount from '../../libs/models/BankAccount';
-import * as ReimbursementAccountProps from '../ReimbursementAccount/reimbursementAccountPropTypes';
-import userPropTypes from '../settings/userPropTypes';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import ScrollViewWithContext from '@components/ScrollViewWithContext';
+import useNetwork from '@hooks/useNetwork';
+import compose from '@libs/compose';
+import BankAccount from '@libs/models/BankAccount';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import userPropTypes from '@pages/settings/userPropTypes';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
-import ScrollViewWithContext from '../../components/ScrollViewWithContext';
-import useNetwork from '../../hooks/useNetwork';
const propTypes = {
shouldSkipVBBACall: PropTypes.bool,
diff --git a/src/pages/workspace/WorkspaceResetBankAccountModal.js b/src/pages/workspace/WorkspaceResetBankAccountModal.js
index ff7bcb51e939..434c09f0ac04 100644
--- a/src/pages/workspace/WorkspaceResetBankAccountModal.js
+++ b/src/pages/workspace/WorkspaceResetBankAccountModal.js
@@ -1,15 +1,15 @@
import lodashGet from 'lodash/get';
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import ConfirmModal from '../../components/ConfirmModal';
-import * as BankAccounts from '../../libs/actions/BankAccounts';
-import * as ReimbursementAccountProps from '../ReimbursementAccount/reimbursementAccountPropTypes';
-import Text from '../../components/Text';
-import styles from '../../styles/styles';
-import BankAccount from '../../libs/models/BankAccount';
-import ONYXKEYS from '../../ONYXKEYS';
-import useLocalize from '../../hooks/useLocalize';
+import ConfirmModal from '@components/ConfirmModal';
+import Text from '@components/Text';
+import useLocalize from '@hooks/useLocalize';
+import BankAccount from '@libs/models/BankAccount';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Reimbursement account data */
diff --git a/src/pages/workspace/WorkspaceSettingsCurrencyPage.js b/src/pages/workspace/WorkspaceSettingsCurrencyPage.js
index a8f473bb1a0b..ce1e1d7b8966 100644
--- a/src/pages/workspace/WorkspaceSettingsCurrencyPage.js
+++ b/src/pages/workspace/WorkspaceSettingsCurrencyPage.js
@@ -1,19 +1,19 @@
-import React, {useState, useCallback} from 'react';
-import _ from 'underscore';
-import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
-import useLocalize from '../../hooks/useLocalize';
-import ScreenWrapper from '../../components/ScreenWrapper';
-import HeaderWithBackButton from '../../components/HeaderWithBackButton';
-import SelectionList from '../../components/SelectionList';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
+import React, {useCallback, useState} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import _ from 'underscore';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import SelectionList from '@components/SelectionList';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as Policy from '@userActions/Policy';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import {policyDefaultProps, policyPropTypes} from './withPolicy';
-import * as Policy from '../../libs/actions/Policy';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
const propTypes = {
diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js
index fd975ebc9247..9d1000179291 100644
--- a/src/pages/workspace/WorkspaceSettingsPage.js
+++ b/src/pages/workspace/WorkspaceSettingsPage.js
@@ -1,31 +1,31 @@
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
import React, {useCallback} from 'react';
import {Keyboard, View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import lodashGet from 'lodash/get';
-import ONYXKEYS from '../../ONYXKEYS';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import * as Policy from '../../libs/actions/Policy';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import AvatarWithImagePicker from '../../components/AvatarWithImagePicker';
-import CONST from '../../CONST';
-import TextInput from '../../components/TextInput';
+import Avatar from '@components/Avatar';
+import AvatarWithImagePicker from '@components/AvatarWithImagePicker';
+import Form from '@components/Form';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {withNetwork} from '@components/OnyxProvider';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import withWindowDimensions, {windowDimensionsPropTypes} from '@components/withWindowDimensions';
+import useLocalize from '@hooks/useLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as ReportUtils from '@libs/ReportUtils';
+import * as UserUtils from '@libs/UserUtils';
+import styles from '@styles/styles';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import withPolicy, {policyDefaultProps, policyPropTypes} from './withPolicy';
import WorkspacePageWithSections from './WorkspacePageWithSections';
-import withPolicy, {policyPropTypes, policyDefaultProps} from './withPolicy';
-import {withNetwork} from '../../components/OnyxProvider';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
-import Form from '../../components/Form';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as UserUtils from '../../libs/UserUtils';
-import Avatar from '../../components/Avatar';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import withWindowDimensions, {windowDimensionsPropTypes} from '../../components/withWindowDimensions';
-import MenuItemWithTopDescription from '../../components/MenuItemWithTopDescription';
-import Text from '../../components/Text';
-import useLocalize from '../../hooks/useLocalize';
const propTypes = {
/** Constant, list of available currencies */
diff --git a/src/pages/workspace/WorkspacesListPage.js b/src/pages/workspace/WorkspacesListPage.js
index 5a2e01562cc1..572dd9d1152f 100755
--- a/src/pages/workspace/WorkspacesListPage.js
+++ b/src/pages/workspace/WorkspacesListPage.js
@@ -1,34 +1,34 @@
+import PropTypes from 'prop-types';
import React, {useMemo} from 'react';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
import _ from 'underscore';
-import Navigation from '../../libs/Navigation/Navigation';
-import ROUTES from '../../ROUTES';
-import ONYXKEYS from '../../ONYXKEYS';
-import CONST from '../../CONST';
-import styles from '../../styles/styles';
-import compose from '../../libs/compose';
-import OfflineWithFeedback from '../../components/OfflineWithFeedback';
-import * as Expensicons from '../../components/Icon/Expensicons';
-import themeColors from '../../styles/themes/default';
-import * as PolicyUtils from '../../libs/PolicyUtils';
-import MenuItem from '../../components/MenuItem';
-import * as Policy from '../../libs/actions/Policy';
-import policyMemberPropType from '../policyMemberPropType';
-import Button from '../../components/Button';
-import * as ReimbursementAccountProps from '../ReimbursementAccount/reimbursementAccountPropTypes';
-import * as ReportUtils from '../../libs/ReportUtils';
-import * as CurrencyUtils from '../../libs/CurrencyUtils';
+import Button from '@components/Button';
+import FeatureList from '@components/FeatureList';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import IllustratedHeaderPageLayout from '@components/IllustratedHeaderPageLayout';
+import * as LottieAnimations from '@components/LottieAnimations';
+import MenuItem from '@components/MenuItem';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import useLocalize from '@hooks/useLocalize';
+import useNetwork from '@hooks/useNetwork';
+import usePermissions from '@hooks/usePermissions';
+import compose from '@libs/compose';
+import * as CurrencyUtils from '@libs/CurrencyUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReportUtils from '@libs/ReportUtils';
+import policyMemberPropType from '@pages/policyMemberPropType';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as App from '@userActions/App';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import SCREENS from '@src/SCREENS';
import withPolicyAndFullscreenLoading from './withPolicyAndFullscreenLoading';
-import * as App from '../../libs/actions/App';
-import useLocalize from '../../hooks/useLocalize';
-import useNetwork from '../../hooks/useNetwork';
-import usePermissions from '../../hooks/usePermissions';
-import IllustratedHeaderPageLayout from '../../components/IllustratedHeaderPageLayout';
-import SCREENS from '../../SCREENS';
-import * as LottieAnimations from '../../components/LottieAnimations';
-import * as Illustrations from '../../components/Icon/Illustrations';
-import FeatureList from '../../components/FeatureList';
const propTypes = {
/** The list of this user's policies */
diff --git a/src/pages/workspace/bills/WorkspaceBillsFirstSection.js b/src/pages/workspace/bills/WorkspaceBillsFirstSection.js
index b0fc0e99c8f9..d71614f8a078 100644
--- a/src/pages/workspace/bills/WorkspaceBillsFirstSection.js
+++ b/src/pages/workspace/bills/WorkspaceBillsFirstSection.js
@@ -1,20 +1,20 @@
+import Str from 'expensify-common/lib/str';
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
-import Str from 'expensify-common/lib/str';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
-import CopyTextToClipboard from '../../../components/CopyTextToClipboard';
-import * as Link from '../../../libs/actions/Link';
-import compose from '../../../libs/compose';
-import ONYXKEYS from '../../../ONYXKEYS';
-import userPropTypes from '../../settings/userPropTypes';
-import TextLink from '../../../components/TextLink';
+import CopyTextToClipboard from '@components/CopyTextToClipboard';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import userPropTypes from '@pages/settings/userPropTypes';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** The policy ID currently being configured */
diff --git a/src/pages/workspace/bills/WorkspaceBillsNoVBAView.js b/src/pages/workspace/bills/WorkspaceBillsNoVBAView.js
index 8c16cbb195cc..8bca8e9067ee 100644
--- a/src/pages/workspace/bills/WorkspaceBillsNoVBAView.js
+++ b/src/pages/workspace/bills/WorkspaceBillsNoVBAView.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
+import ConnectBankAccountButton from '@components/ConnectBankAccountButton';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
import WorkspaceBillsFirstSection from './WorkspaceBillsFirstSection';
-import ConnectBankAccountButton from '../../../components/ConnectBankAccountButton';
const propTypes = {
/** The policy ID currently being configured */
diff --git a/src/pages/workspace/bills/WorkspaceBillsPage.js b/src/pages/workspace/bills/WorkspaceBillsPage.js
index 5cb590895e0d..c607071a4365 100644
--- a/src/pages/workspace/bills/WorkspaceBillsPage.js
+++ b/src/pages/workspace/bills/WorkspaceBillsPage.js
@@ -1,10 +1,10 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
+import React from 'react';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
+import CONST from '@src/CONST';
import WorkspaceBillsNoVBAView from './WorkspaceBillsNoVBAView';
import WorkspaceBillsVBAView from './WorkspaceBillsVBAView';
-import WorkspacePageWithSections from '../WorkspacePageWithSections';
-import CONST from '../../../CONST';
const propTypes = {
/** The route object passed to this page from the navigator */
diff --git a/src/pages/workspace/bills/WorkspaceBillsVBAView.js b/src/pages/workspace/bills/WorkspaceBillsVBAView.js
index c35b3400e7d1..08e5349e2e1f 100644
--- a/src/pages/workspace/bills/WorkspaceBillsVBAView.js
+++ b/src/pages/workspace/bills/WorkspaceBillsVBAView.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
-import * as Link from '../../../libs/actions/Link';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
import WorkspaceBillsFirstSection from './WorkspaceBillsFirstSection';
const propTypes = {
diff --git a/src/pages/workspace/card/WorkspaceCardNoVBAView.js b/src/pages/workspace/card/WorkspaceCardNoVBAView.js
index b1a1dcf0b793..a8ad276dd0ce 100644
--- a/src/pages/workspace/card/WorkspaceCardNoVBAView.js
+++ b/src/pages/workspace/card/WorkspaceCardNoVBAView.js
@@ -1,13 +1,13 @@
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {View} from 'react-native';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import UnorderedList from '../../../components/UnorderedList';
-import Section from '../../../components/Section';
-import ConnectBankAccountButton from '../../../components/ConnectBankAccountButton';
+import ConnectBankAccountButton from '@components/ConnectBankAccountButton';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import UnorderedList from '@components/UnorderedList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
const propTypes = {
/** The policy ID currently being configured */
diff --git a/src/pages/workspace/card/WorkspaceCardPage.js b/src/pages/workspace/card/WorkspaceCardPage.js
index 2f5527c49cf0..55220b85ce63 100644
--- a/src/pages/workspace/card/WorkspaceCardPage.js
+++ b/src/pages/workspace/card/WorkspaceCardPage.js
@@ -1,11 +1,11 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
+import React from 'react';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
+import CONST from '@src/CONST';
import WorkspaceCardNoVBAView from './WorkspaceCardNoVBAView';
import WorkspaceCardVBANoECardView from './WorkspaceCardVBANoECardView';
import WorkspaceCardVBAWithECardView from './WorkspaceCardVBAWithECardView';
-import WorkspacePageWithSections from '../WorkspacePageWithSections';
-import CONST from '../../../CONST';
const propTypes = {
/** The route object passed to this page from the navigator */
diff --git a/src/pages/workspace/card/WorkspaceCardVBANoECardView.js b/src/pages/workspace/card/WorkspaceCardVBANoECardView.js
index 5c93b8858de4..0ac81230b32e 100644
--- a/src/pages/workspace/card/WorkspaceCardVBANoECardView.js
+++ b/src/pages/workspace/card/WorkspaceCardVBANoECardView.js
@@ -1,19 +1,19 @@
import React from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import Text from '../../../components/Text';
-import Button from '../../../components/Button';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import UnorderedList from '../../../components/UnorderedList';
-import Section from '../../../components/Section';
-import * as Link from '../../../libs/actions/Link';
-import ONYXKEYS from '../../../ONYXKEYS';
-import compose from '../../../libs/compose';
-import CONST from '../../../CONST';
-import userPropTypes from '../../settings/userPropTypes';
+import Button from '@components/Button';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import UnorderedList from '@components/UnorderedList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import userPropTypes from '@pages/settings/userPropTypes';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
const propTypes = {
/** Information about the logged in user's account */
diff --git a/src/pages/workspace/card/WorkspaceCardVBAWithECardView.js b/src/pages/workspace/card/WorkspaceCardVBAWithECardView.js
index 7f9971f00c1b..582a85109461 100644
--- a/src/pages/workspace/card/WorkspaceCardVBAWithECardView.js
+++ b/src/pages/workspace/card/WorkspaceCardVBAWithECardView.js
@@ -1,13 +1,13 @@
import React from 'react';
import {View} from 'react-native';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import UnorderedList from '../../../components/UnorderedList';
-import * as Link from '../../../libs/actions/Link';
-import Section from '../../../components/Section';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import UnorderedList from '@components/UnorderedList';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/workspace/invoices/WorkspaceInvoicesFirstSection.js b/src/pages/workspace/invoices/WorkspaceInvoicesFirstSection.js
index 7c47476e1c7b..78fe7cdae1cb 100644
--- a/src/pages/workspace/invoices/WorkspaceInvoicesFirstSection.js
+++ b/src/pages/workspace/invoices/WorkspaceInvoicesFirstSection.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
-import * as Link from '../../../libs/actions/Link';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
const propTypes = {
/** The policy ID currently being configured */
diff --git a/src/pages/workspace/invoices/WorkspaceInvoicesNoVBAView.js b/src/pages/workspace/invoices/WorkspaceInvoicesNoVBAView.js
index 5348e49ee599..6f334cd10b0a 100644
--- a/src/pages/workspace/invoices/WorkspaceInvoicesNoVBAView.js
+++ b/src/pages/workspace/invoices/WorkspaceInvoicesNoVBAView.js
@@ -1,13 +1,13 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
+import ConnectBankAccountButton from '@components/ConnectBankAccountButton';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
import WorkspaceInvoicesFirstSection from './WorkspaceInvoicesFirstSection';
-import ConnectBankAccountButton from '../../../components/ConnectBankAccountButton';
const propTypes = {
/** The policy ID currently being configured */
diff --git a/src/pages/workspace/invoices/WorkspaceInvoicesPage.js b/src/pages/workspace/invoices/WorkspaceInvoicesPage.js
index bfc1988211ce..8bc0c4484100 100644
--- a/src/pages/workspace/invoices/WorkspaceInvoicesPage.js
+++ b/src/pages/workspace/invoices/WorkspaceInvoicesPage.js
@@ -1,10 +1,10 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import WorkspacePageWithSections from '../WorkspacePageWithSections';
+import React from 'react';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
+import CONST from '@src/CONST';
import WorkspaceInvoicesNoVBAView from './WorkspaceInvoicesNoVBAView';
import WorkspaceInvoicesVBAView from './WorkspaceInvoicesVBAView';
-import CONST from '../../../CONST';
const propTypes = {
/** The route object passed to this page from the navigator */
diff --git a/src/pages/workspace/invoices/WorkspaceInvoicesVBAView.js b/src/pages/workspace/invoices/WorkspaceInvoicesVBAView.js
index 0f7dd8b340fc..0958ba9688e5 100644
--- a/src/pages/workspace/invoices/WorkspaceInvoicesVBAView.js
+++ b/src/pages/workspace/invoices/WorkspaceInvoicesVBAView.js
@@ -1,14 +1,14 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
import WorkspaceInvoicesFirstSection from './WorkspaceInvoicesFirstSection';
-import * as Link from '../../../libs/actions/Link';
const propTypes = {
/** The policy ID currently being configured */
diff --git a/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js b/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js
index 026441c665a2..14338424e11d 100644
--- a/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js
+++ b/src/pages/workspace/reimburse/WorkspaceRateAndUnitPage.js
@@ -1,28 +1,28 @@
+import lodashGet from 'lodash/get';
import React from 'react';
import {Keyboard, View} from 'react-native';
-import _ from 'underscore';
-import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
-import ONYXKEYS from '../../../ONYXKEYS';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import styles from '../../../styles/styles';
-import compose from '../../../libs/compose';
-import * as Policy from '../../../libs/actions/Policy';
-import * as PolicyUtils from '../../../libs/PolicyUtils';
-import CONST from '../../../CONST';
-import Picker from '../../../components/Picker';
-import TextInput from '../../../components/TextInput';
-import WorkspacePageWithSections from '../WorkspacePageWithSections';
-import withPolicy, {policyPropTypes, policyDefaultProps} from '../withPolicy';
-import {withNetwork} from '../../../components/OnyxProvider';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
-import Form from '../../../components/Form';
-import Navigation from '../../../libs/Navigation/Navigation';
-import ROUTES from '../../../ROUTES';
-import getPermittedDecimalSeparator from '../../../libs/getPermittedDecimalSeparator';
-import * as BankAccounts from '../../../libs/actions/BankAccounts';
-import * as ReimbursementAccountProps from '../../ReimbursementAccount/reimbursementAccountPropTypes';
-import * as NumberUtils from '../../../libs/NumberUtils';
+import _ from 'underscore';
+import Form from '@components/Form';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {withNetwork} from '@components/OnyxProvider';
+import Picker from '@components/Picker';
+import TextInput from '@components/TextInput';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import getPermittedDecimalSeparator from '@libs/getPermittedDecimalSeparator';
+import Navigation from '@libs/Navigation/Navigation';
+import * as NumberUtils from '@libs/NumberUtils';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import withPolicy, {policyDefaultProps, policyPropTypes} from '@pages/workspace/withPolicy';
+import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
const propTypes = {
/** Bank account attached to free plan */
diff --git a/src/pages/workspace/reimburse/WorkspaceReimbursePage.js b/src/pages/workspace/reimburse/WorkspaceReimbursePage.js
index 9d1495c2a11f..d19cde6a0553 100644
--- a/src/pages/workspace/reimburse/WorkspaceReimbursePage.js
+++ b/src/pages/workspace/reimburse/WorkspaceReimbursePage.js
@@ -1,11 +1,11 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
+import React from 'react';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import withPolicy, {policyPropTypes} from '@pages/workspace/withPolicy';
+import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
+import CONST from '@src/CONST';
import WorkspaceReimburseView from './WorkspaceReimburseView';
-import WorkspacePageWithSections from '../WorkspacePageWithSections';
-import CONST from '../../../CONST';
-import compose from '../../../libs/compose';
-import withPolicy, {policyPropTypes} from '../withPolicy';
const propTypes = {
/** The route object passed to this page from the navigator */
diff --git a/src/pages/workspace/reimburse/WorkspaceReimburseSection.js b/src/pages/workspace/reimburse/WorkspaceReimburseSection.js
index eb8305f23140..4a6c32287018 100644
--- a/src/pages/workspace/reimburse/WorkspaceReimburseSection.js
+++ b/src/pages/workspace/reimburse/WorkspaceReimburseSection.js
@@ -1,20 +1,20 @@
-import React, {useState, useEffect} from 'react';
+import lodashGet from 'lodash/get';
import PropTypes from 'prop-types';
+import React, {useEffect, useState} from 'react';
import {ActivityIndicator, View} from 'react-native';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import themeColors from '../../../styles/themes/default';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
-import * as Link from '../../../libs/actions/Link';
-import BankAccount from '../../../libs/models/BankAccount';
-import * as ReimbursementAccountProps from '../../ReimbursementAccount/reimbursementAccountPropTypes';
-import networkPropTypes from '../../../components/networkPropTypes';
-import CONST from '../../../CONST';
-import ConnectBankAccountButton from '../../../components/ConnectBankAccountButton';
+import ConnectBankAccountButton from '@components/ConnectBankAccountButton';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import networkPropTypes from '@components/networkPropTypes';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import BankAccount from '@libs/models/BankAccount';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import styles from '@styles/styles';
+import themeColors from '@styles/themes/default';
+import * as Link from '@userActions/Link';
+import CONST from '@src/CONST';
const propTypes = {
/** Policy values needed in the component */
diff --git a/src/pages/workspace/reimburse/WorkspaceReimburseView.js b/src/pages/workspace/reimburse/WorkspaceReimburseView.js
index 6b520b65eff2..5085792ed027 100644
--- a/src/pages/workspace/reimburse/WorkspaceReimburseView.js
+++ b/src/pages/workspace/reimburse/WorkspaceReimburseView.js
@@ -1,31 +1,31 @@
-import React, {useState, useEffect, useCallback} from 'react';
+import lodashGet from 'lodash/get';
+import PropTypes from 'prop-types';
+import React, {useCallback, useEffect, useState} from 'react';
import {View} from 'react-native';
import {withOnyx} from 'react-native-onyx';
-import PropTypes from 'prop-types';
-import lodashGet from 'lodash/get';
import _ from 'underscore';
-import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
-import Navigation from '../../../libs/Navigation/Navigation';
-import CopyTextToClipboard from '../../../components/CopyTextToClipboard';
-import * as Link from '../../../libs/actions/Link';
-import compose from '../../../libs/compose';
-import * as Policy from '../../../libs/actions/Policy';
-import * as PolicyUtils from '../../../libs/PolicyUtils';
-import CONST from '../../../CONST';
-import ROUTES from '../../../ROUTES';
-import ONYXKEYS from '../../../ONYXKEYS';
-import * as ReimbursementAccountProps from '../../ReimbursementAccount/reimbursementAccountPropTypes';
-import {withNetwork} from '../../../components/OnyxProvider';
-import networkPropTypes from '../../../components/networkPropTypes';
+import CopyTextToClipboard from '@components/CopyTextToClipboard';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import networkPropTypes from '@components/networkPropTypes';
+import OfflineWithFeedback from '@components/OfflineWithFeedback';
+import {withNetwork} from '@components/OnyxProvider';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import compose from '@libs/compose';
+import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
+import * as ReimbursementAccountProps from '@pages/ReimbursementAccount/reimbursementAccountPropTypes';
+import styles from '@styles/styles';
+import * as BankAccounts from '@userActions/BankAccounts';
+import * as Link from '@userActions/Link';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
import WorkspaceReimburseSection from './WorkspaceReimburseSection';
-import * as BankAccounts from '../../../libs/actions/BankAccounts';
-import OfflineWithFeedback from '../../../components/OfflineWithFeedback';
const propTypes = {
/** Policy values needed in the component */
diff --git a/src/pages/workspace/travel/WorkspaceTravelNoVBAView.js b/src/pages/workspace/travel/WorkspaceTravelNoVBAView.js
index 254162e29aed..67be0fdca9fb 100644
--- a/src/pages/workspace/travel/WorkspaceTravelNoVBAView.js
+++ b/src/pages/workspace/travel/WorkspaceTravelNoVBAView.js
@@ -1,12 +1,12 @@
+import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
-import PropTypes from 'prop-types';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
-import ConnectBankAccountButton from '../../../components/ConnectBankAccountButton';
+import ConnectBankAccountButton from '@components/ConnectBankAccountButton';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
const propTypes = {
/** The policy ID currently being configured */
diff --git a/src/pages/workspace/travel/WorkspaceTravelPage.js b/src/pages/workspace/travel/WorkspaceTravelPage.js
index 8f8a174a5876..a88e180cc7b6 100644
--- a/src/pages/workspace/travel/WorkspaceTravelPage.js
+++ b/src/pages/workspace/travel/WorkspaceTravelPage.js
@@ -1,10 +1,10 @@
-import React from 'react';
import PropTypes from 'prop-types';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import WorkspacePageWithSections from '../WorkspacePageWithSections';
+import React from 'react';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import WorkspacePageWithSections from '@pages/workspace/WorkspacePageWithSections';
+import CONST from '@src/CONST';
import WorkspaceTravelNoVBAView from './WorkspaceTravelNoVBAView';
import WorkspaceTravelVBAView from './WorkspaceTravelVBAView';
-import CONST from '../../../CONST';
const propTypes = {
/** The route object passed to this page from the navigator */
diff --git a/src/pages/workspace/travel/WorkspaceTravelVBAView.js b/src/pages/workspace/travel/WorkspaceTravelVBAView.js
index 8156b0334b3d..6d5620d8c939 100644
--- a/src/pages/workspace/travel/WorkspaceTravelVBAView.js
+++ b/src/pages/workspace/travel/WorkspaceTravelVBAView.js
@@ -1,14 +1,14 @@
import React from 'react';
import {View} from 'react-native';
-import Text from '../../../components/Text';
-import styles from '../../../styles/styles';
-import withLocalize, {withLocalizePropTypes} from '../../../components/withLocalize';
-import * as Expensicons from '../../../components/Icon/Expensicons';
-import * as Illustrations from '../../../components/Icon/Illustrations';
-import Section from '../../../components/Section';
-import * as Link from '../../../libs/actions/Link';
-import * as Report from '../../../libs/actions/Report';
-import CONST from '../../../CONST';
+import * as Expensicons from '@components/Icon/Expensicons';
+import * as Illustrations from '@components/Icon/Illustrations';
+import Section from '@components/Section';
+import Text from '@components/Text';
+import withLocalize, {withLocalizePropTypes} from '@components/withLocalize';
+import styles from '@styles/styles';
+import * as Link from '@userActions/Link';
+import * as Report from '@userActions/Report';
+import CONST from '@src/CONST';
const propTypes = {
...withLocalizePropTypes,
diff --git a/src/pages/workspace/withPolicy.js b/src/pages/workspace/withPolicy.js
index 6ca0ca67fce1..cc0865dfcfdd 100644
--- a/src/pages/workspace/withPolicy.js
+++ b/src/pages/workspace/withPolicy.js
@@ -1,14 +1,14 @@
-import _ from 'underscore';
+import {useNavigationState} from '@react-navigation/native';
import lodashGet from 'lodash/get';
-import React from 'react';
import PropTypes from 'prop-types';
+import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import {useNavigationState} from '@react-navigation/native';
-import CONST from '../../CONST';
-import getComponentDisplayName from '../../libs/getComponentDisplayName';
-import * as Policy from '../../libs/actions/Policy';
-import ONYXKEYS from '../../ONYXKEYS';
-import policyMemberPropType from '../policyMemberPropType';
+import _ from 'underscore';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import policyMemberPropType from '@pages/policyMemberPropType';
+import * as Policy from '@userActions/Policy';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
/**
* @param {Object} route
@@ -105,7 +105,7 @@ export default function (WrappedComponent) {
WithPolicy.propTypes = propTypes;
WithPolicy.defaultProps = defaultProps;
WithPolicy.displayName = `withPolicy(${getComponentDisplayName(WrappedComponent)})`;
- const withPolicy = React.forwardRef((props, ref) => (
+ const WithPolicyWithRef = React.forwardRef((props, ref) => (
));
+ WithPolicyWithRef.displayName = 'WithPolicyWithRef';
+
return withOnyx({
policy: {
key: (props) => `${ONYXKEYS.COLLECTION.POLICY}${getPolicyIDFromRoute(props.route)}`,
@@ -126,7 +128,7 @@ export default function (WrappedComponent) {
policyMembersDraft: {
key: (props) => `${ONYXKEYS.COLLECTION.POLICY_MEMBERS_DRAFTS}${getPolicyIDFromRoute(props.route)}`,
},
- })(withPolicy);
+ })(WithPolicyWithRef);
}
export {policyPropTypes, policyDefaultProps};
diff --git a/src/pages/workspace/withPolicyAndFullscreenLoading.js b/src/pages/workspace/withPolicyAndFullscreenLoading.js
index 8265169434a3..2911eadccf5f 100644
--- a/src/pages/workspace/withPolicyAndFullscreenLoading.js
+++ b/src/pages/workspace/withPolicyAndFullscreenLoading.js
@@ -1,13 +1,13 @@
+import isEmpty from 'lodash/isEmpty';
+import omit from 'lodash/omit';
import PropTypes from 'prop-types';
import React from 'react';
import {withOnyx} from 'react-native-onyx';
-import isEmpty from 'lodash/isEmpty';
-import omit from 'lodash/omit';
-import compose from '../../libs/compose';
-import ONYXKEYS from '../../ONYXKEYS';
-import withPolicy, {policyPropTypes, policyDefaultProps} from './withPolicy';
-import getComponentDisplayName from '../../libs/getComponentDisplayName';
-import FullscreenLoadingIndicator from '../../components/FullscreenLoadingIndicator';
+import FullscreenLoadingIndicator from '@components/FullscreenLoadingIndicator';
+import compose from '@libs/compose';
+import getComponentDisplayName from '@libs/getComponentDisplayName';
+import ONYXKEYS from '@src/ONYXKEYS';
+import withPolicy, {policyDefaultProps, policyPropTypes} from './withPolicy';
export default function (WrappedComponent) {
const propTypes = {
@@ -46,7 +46,7 @@ export default function (WrappedComponent) {
WithPolicyAndFullscreenLoading.defaultProps = defaultProps;
WithPolicyAndFullscreenLoading.displayName = `WithPolicyAndFullscreenLoading(${getComponentDisplayName(WrappedComponent)})`;
- const withPolicyAndFullscreenLoading = React.forwardRef((props, ref) => (
+ const WithPolicyAndFullscreenLoadingWithRef = React.forwardRef((props, ref) => (
));
+ WithPolicyAndFullscreenLoadingWithRef.displayName = 'WithPolicyAndFullscreenLoadingWithRef';
+
return compose(
withPolicy,
withOnyx({
@@ -61,5 +63,5 @@ export default function (WrappedComponent) {
key: ONYXKEYS.IS_LOADING_REPORT_DATA,
},
}),
- )(withPolicyAndFullscreenLoading);
+ )(WithPolicyAndFullscreenLoadingWithRef);
}
diff --git a/src/setup/index.js b/src/setup/index.js
index 5e92bff35ba1..aac6f1e4e732 100644
--- a/src/setup/index.js
+++ b/src/setup/index.js
@@ -1,12 +1,12 @@
import {I18nManager} from 'react-native';
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../ONYXKEYS';
-import CONST from '../CONST';
+import intlPolyfill from '@libs/IntlPolyfill';
+import * as Metrics from '@libs/Metrics';
+import * as Device from '@userActions/Device';
+import exposeGlobalMemoryOnlyKeysMethods from '@userActions/MemoryOnlyKeys/exposeGlobalMemoryOnlyKeysMethods';
+import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import platformSetup from './platformSetup';
-import * as Metrics from '../libs/Metrics';
-import * as Device from '../libs/actions/Device';
-import intlPolyfill from '../libs/IntlPolyfill';
-import exposeGlobalMemoryOnlyKeysMethods from '../libs/actions/MemoryOnlyKeys/exposeGlobalMemoryOnlyKeysMethods';
export default function () {
/*
diff --git a/src/setup/platformSetup/index.desktop.js b/src/setup/platformSetup/index.desktop.js
index 0fff03ed252b..ab485b1855f1 100644
--- a/src/setup/platformSetup/index.desktop.js
+++ b/src/setup/platformSetup/index.desktop.js
@@ -1,10 +1,10 @@
import {AppRegistry} from 'react-native';
-import Config from '../../CONFIG';
-import LocalNotification from '../../libs/Notification/LocalNotification';
-import DateUtils from '../../libs/DateUtils';
+import DateUtils from '@libs/DateUtils';
+import Navigation from '@libs/Navigation/Navigation';
+import LocalNotification from '@libs/Notification/LocalNotification';
+import Config from '@src/CONFIG';
+import ROUTES from '@src/ROUTES';
import ELECTRON_EVENTS from '../../../desktop/ELECTRON_EVENTS';
-import ROUTES from '../../ROUTES';
-import Navigation from '../../libs/Navigation/Navigation';
export default function () {
AppRegistry.runApplication(Config.APP_NAME, {
diff --git a/src/setup/platformSetup/index.native.js b/src/setup/platformSetup/index.native.js
index 470bef78848f..09a39e13386e 100644
--- a/src/setup/platformSetup/index.native.js
+++ b/src/setup/platformSetup/index.native.js
@@ -1,8 +1,8 @@
import crashlytics from '@react-native-firebase/crashlytics';
-import CONFIG from '../../CONFIG';
-import PushNotification from '../../libs/Notification/PushNotification';
-import Performance from '../../libs/Performance';
-import subscribeToReportCommentPushNotifications from '../../libs/Notification/PushNotification/subscribeToReportCommentPushNotifications';
+import PushNotification from '@libs/Notification/PushNotification';
+import subscribeToReportCommentPushNotifications from '@libs/Notification/PushNotification/subscribeToReportCommentPushNotifications';
+import Performance from '@libs/Performance';
+import CONFIG from '@src/CONFIG';
export default function () {
// We do not want to send crash reports if we are on a locally built release version of the app.
diff --git a/src/setup/platformSetup/index.website.js b/src/setup/platformSetup/index.website.js
index e859005c9abe..d26268cd94bf 100644
--- a/src/setup/platformSetup/index.website.js
+++ b/src/setup/platformSetup/index.website.js
@@ -1,13 +1,11 @@
import {AppRegistry} from 'react-native';
-
// This is a polyfill for InternetExplorer to support the modern KeyboardEvent.key and KeyboardEvent.code instead of KeyboardEvent.keyCode
import 'shim-keyboard-event-key';
-
-import checkForUpdates from '../../libs/checkForUpdates';
-import Config from '../../CONFIG';
-import DateUtils from '../../libs/DateUtils';
+import checkForUpdates from '@libs/checkForUpdates';
+import DateUtils from '@libs/DateUtils';
+import Visibility from '@libs/Visibility';
+import Config from '@src/CONFIG';
import pkg from '../../../package.json';
-import Visibility from '../../libs/Visibility';
/**
* Download the latest app version from the server, and if it is different than the current one,
diff --git a/src/stories/AddressSearch.stories.js b/src/stories/AddressSearch.stories.js
index 35f7e3a07596..8b9223bc5ea2 100644
--- a/src/stories/AddressSearch.stories.js
+++ b/src/stories/AddressSearch.stories.js
@@ -1,5 +1,5 @@
import React, {useState} from 'react';
-import AddressSearch from '../components/AddressSearch';
+import AddressSearch from '@components/AddressSearch';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/Banner.stories.js b/src/stories/Banner.stories.js
index c7c27cb52352..3a6f454843d1 100644
--- a/src/stories/Banner.stories.js
+++ b/src/stories/Banner.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Banner from '../components/Banner';
+import Banner from '@components/Banner';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/Button.stories.js b/src/stories/Button.stories.js
index 9fec08800f0a..2bf254b9f382 100644
--- a/src/stories/Button.stories.js
+++ b/src/stories/Button.stories.js
@@ -1,8 +1,8 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, {useCallback, useState} from 'react';
import {View} from 'react-native';
-import Button from '../components/Button';
-import Text from '../components/Text';
+import Button from '@components/Button';
+import Text from '@components/Text';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/ButtonWithDropdownMenu.stories.js b/src/stories/ButtonWithDropdownMenu.stories.js
index 88fa73c20fa1..b87bdc321d45 100644
--- a/src/stories/ButtonWithDropdownMenu.stories.js
+++ b/src/stories/ButtonWithDropdownMenu.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import ButtonWithDropdownMenu from '../components/ButtonWithDropdownMenu';
+import ButtonWithDropdownMenu from '@components/ButtonWithDropdownMenu';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/Checkbox.stories.js b/src/stories/Checkbox.stories.js
index 4a7de2c29753..fc5b63347c71 100644
--- a/src/stories/Checkbox.stories.js
+++ b/src/stories/Checkbox.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Checkbox from '../components/Checkbox';
+import Checkbox from '@components/Checkbox';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/CheckboxWithLabel.stories.js b/src/stories/CheckboxWithLabel.stories.js
index 61ec66a6b2f6..e8d45f434b16 100644
--- a/src/stories/CheckboxWithLabel.stories.js
+++ b/src/stories/CheckboxWithLabel.stories.js
@@ -1,7 +1,7 @@
import React from 'react';
-import CheckboxWithLabel from '../components/CheckboxWithLabel';
-import Text from '../components/Text';
-import styles from '../styles/styles';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import Text from '@components/Text';
+import styles from '@styles/styles';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/Composer.stories.js b/src/stories/Composer.stories.js
index 50039d7d537a..fc817ef2c86d 100644
--- a/src/stories/Composer.stories.js
+++ b/src/stories/Composer.stories.js
@@ -1,14 +1,14 @@
import ExpensiMark from 'expensify-common/lib/ExpensiMark';
import React, {useState} from 'react';
-import {View, Image} from 'react-native';
-import Composer from '../components/Composer';
-import RenderHTML from '../components/RenderHTML';
-import Text from '../components/Text';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import * as StyleUtils from '../styles/StyleUtils';
-import CONST from '../CONST';
-import withNavigationFallback from '../components/withNavigationFallback';
+import {Image, View} from 'react-native';
+import Composer from '@components/Composer';
+import RenderHTML from '@components/RenderHTML';
+import Text from '@components/Text';
+import withNavigationFallback from '@components/withNavigationFallback';
+import styles from '@styles/styles';
+import * as StyleUtils from '@styles/StyleUtils';
+import themeColors from '@styles/themes/default';
+import CONST from '@src/CONST';
const ComposerWithNavigation = withNavigationFallback(Composer);
diff --git a/src/stories/Datepicker.stories.js b/src/stories/Datepicker.stories.js
index c4a002c6f88d..65bbec9d7f39 100644
--- a/src/stories/Datepicker.stories.js
+++ b/src/stories/Datepicker.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import DatePicker from '../components/DatePicker';
+import DatePicker from '@components/DatePicker';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/DragAndDrop.stories.js b/src/stories/DragAndDrop.stories.js
index eb9b6bbed6f2..c594d059b396 100644
--- a/src/stories/DragAndDrop.stories.js
+++ b/src/stories/DragAndDrop.stories.js
@@ -1,10 +1,10 @@
-import React, {useState} from 'react';
-import {View, Image} from 'react-native';
import lodashGet from 'lodash/get';
-import Text from '../components/Text';
-import DragAndDropProvider from '../components/DragAndDrop/Provider';
-import DragAndDropConsumer from '../components/DragAndDrop/Consumer';
-import styles from '../styles/styles';
+import React, {useState} from 'react';
+import {Image, View} from 'react-native';
+import DragAndDropConsumer from '@components/DragAndDrop/Consumer';
+import DragAndDropProvider from '@components/DragAndDrop/Provider';
+import Text from '@components/Text';
+import styles from '@styles/styles';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/EReceipt.stories.js b/src/stories/EReceipt.stories.js
index 56a79e30980b..d4f2b58cb213 100644
--- a/src/stories/EReceipt.stories.js
+++ b/src/stories/EReceipt.stories.js
@@ -1,8 +1,8 @@
/* eslint-disable rulesdir/prefer-actions-set-data */
import React from 'react';
import Onyx from 'react-native-onyx';
-import EReceipt from '../components/EReceipt';
-import ONYXKEYS from '../ONYXKEYS';
+import EReceipt from '@components/EReceipt';
+import ONYXKEYS from '@src/ONYXKEYS';
const transactionData = {
[`${ONYXKEYS.COLLECTION.TRANSACTION}FAKE_1`]: {
diff --git a/src/stories/EReceiptThumbail.stories.js b/src/stories/EReceiptThumbail.stories.js
index 3d8e79957172..32d9c00851ab 100644
--- a/src/stories/EReceiptThumbail.stories.js
+++ b/src/stories/EReceiptThumbail.stories.js
@@ -1,7 +1,7 @@
/* eslint-disable react/jsx-props-no-spreading */
import React from 'react';
import {View} from 'react-native';
-import EReceiptThumbnail from '../components/EReceiptThumbnail';
+import EReceiptThumbnail from '@components/EReceiptThumbnail';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/Form.stories.js b/src/stories/Form.stories.js
index 3f41edda9992..8bcbaf31b600 100644
--- a/src/stories/Form.stories.js
+++ b/src/stories/Form.stories.js
@@ -1,18 +1,18 @@
import React, {useState} from 'react';
import {View} from 'react-native';
-import TextInput from '../components/TextInput';
-import Picker from '../components/Picker';
-import StatePicker from '../components/StatePicker';
-import AddressSearch from '../components/AddressSearch';
-import DatePicker from '../components/DatePicker';
-import * as FormActions from '../libs/actions/FormActions';
-import styles from '../styles/styles';
-import CheckboxWithLabel from '../components/CheckboxWithLabel';
-import Text from '../components/Text';
-import NetworkConnection from '../libs/NetworkConnection';
-import CONST from '../CONST';
-import InputWrapper from '../components/Form/InputWrapper';
-import FormProvider from '../components/Form/FormProvider';
+import AddressSearch from '@components/AddressSearch';
+import CheckboxWithLabel from '@components/CheckboxWithLabel';
+import DatePicker from '@components/DatePicker';
+import FormProvider from '@components/Form/FormProvider';
+import InputWrapper from '@components/Form/InputWrapper';
+import Picker from '@components/Picker';
+import StatePicker from '@components/StatePicker';
+import Text from '@components/Text';
+import TextInput from '@components/TextInput';
+import NetworkConnection from '@libs/NetworkConnection';
+import styles from '@styles/styles';
+import * as FormActions from '@userActions/FormActions';
+import CONST from '@src/CONST';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/FormAlertWithSubmitButton.stories.js b/src/stories/FormAlertWithSubmitButton.stories.js
index 5ac5404f851d..5d64deb74145 100644
--- a/src/stories/FormAlertWithSubmitButton.stories.js
+++ b/src/stories/FormAlertWithSubmitButton.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import FormAlertWithSubmitButton from '../components/FormAlertWithSubmitButton';
+import FormAlertWithSubmitButton from '@components/FormAlertWithSubmitButton';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/Header.stories.js b/src/stories/Header.stories.js
index 78250fa2c35d..8560fba4b27f 100644
--- a/src/stories/Header.stories.js
+++ b/src/stories/Header.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Header from '../components/Header';
+import Header from '@components/Header';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/HeaderWithBackButton.stories.js b/src/stories/HeaderWithBackButton.stories.js
index f7d361feb8c4..38d816b8fdd2 100644
--- a/src/stories/HeaderWithBackButton.stories.js
+++ b/src/stories/HeaderWithBackButton.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import HeaderWithBackButton from '../components/HeaderWithBackButton';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/InlineSystemMessage.stories.js b/src/stories/InlineSystemMessage.stories.js
index 9a4b034ae35b..b7fe21c8b10e 100644
--- a/src/stories/InlineSystemMessage.stories.js
+++ b/src/stories/InlineSystemMessage.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import InlineSystemMessage from '../components/InlineSystemMessage';
+import InlineSystemMessage from '@components/InlineSystemMessage';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/MagicCodeInput.stories.js b/src/stories/MagicCodeInput.stories.js
index 1ea746dd44ac..14b234996ce1 100644
--- a/src/stories/MagicCodeInput.stories.js
+++ b/src/stories/MagicCodeInput.stories.js
@@ -1,5 +1,5 @@
import React, {useState} from 'react';
-import MagicCodeInput from '../components/MagicCodeInput';
+import MagicCodeInput from '@components/MagicCodeInput';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/MenuItem.stories.js b/src/stories/MenuItem.stories.js
index 7046617fe2ae..47b74b1f0ef8 100644
--- a/src/stories/MenuItem.stories.js
+++ b/src/stories/MenuItem.stories.js
@@ -1,7 +1,7 @@
import React from 'react';
-import MenuItem from '../components/MenuItem';
-import Chase from '../../assets/images/bankicons/chase.svg';
-import variables from '../styles/variables';
+import Chase from '@assets/images/bankicons/chase.svg';
+import MenuItem from '@components/MenuItem';
+import variables from '@styles/variables';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/OptionRow.stories.js b/src/stories/OptionRow.stories.js
index d5ad27f2d939..3096940dda5f 100644
--- a/src/stories/OptionRow.stories.js
+++ b/src/stories/OptionRow.stories.js
@@ -1,7 +1,8 @@
import React from 'react';
-import OptionRow from '../components/OptionRow';
-import * as Expensicons from '../components/Icon/Expensicons';
-import OnyxProvider from '../components/OnyxProvider';
+import * as Expensicons from '@components/Icon/Expensicons';
+import OnyxProvider from '@components/OnyxProvider';
+import OptionRow from '@components/OptionRow';
+
/* eslint-disable react/jsx-props-no-spreading */
/**
diff --git a/src/stories/Picker.stories.js b/src/stories/Picker.stories.js
index 19b04f9fa79a..b42cfed8f471 100644
--- a/src/stories/Picker.stories.js
+++ b/src/stories/Picker.stories.js
@@ -1,5 +1,5 @@
import React, {useState} from 'react';
-import Picker from '../components/Picker';
+import Picker from '@components/Picker';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/PopoverMenu.stories.js b/src/stories/PopoverMenu.stories.js
index 5f8fb8994e1f..b860a8343309 100644
--- a/src/stories/PopoverMenu.stories.js
+++ b/src/stories/PopoverMenu.stories.js
@@ -1,9 +1,9 @@
import React from 'react';
import {SafeAreaProvider} from 'react-native-safe-area-context';
-import PopoverMenu from '../components/PopoverMenu';
-import * as Expensicons from '../components/Icon/Expensicons';
-import MenuItem from '../components/MenuItem';
-import themeColors from '../styles/themes/default';
+import * as Expensicons from '@components/Icon/Expensicons';
+import MenuItem from '@components/MenuItem';
+import PopoverMenu from '@components/PopoverMenu';
+import themeColors from '@styles/themes/default';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/ReportActionItemImages.stories.js b/src/stories/ReportActionItemImages.stories.js
index b776d9261e60..fe86f50f7e34 100644
--- a/src/stories/ReportActionItemImages.stories.js
+++ b/src/stories/ReportActionItemImages.stories.js
@@ -1,6 +1,6 @@
import React from 'react';
-import ReportActionItemImages from '../components/ReportActionItem/ReportActionItemImages';
-import PressableWithoutFeedback from '../components/Pressable/PressableWithoutFeedback';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import ReportActionItemImages from '@components/ReportActionItem/ReportActionItemImages';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/SelectionList.stories.js b/src/stories/SelectionList.stories.js
index c4510611306e..28880e1b00d7 100644
--- a/src/stories/SelectionList.stories.js
+++ b/src/stories/SelectionList.stories.js
@@ -1,10 +1,10 @@
import React, {useMemo, useState} from 'react';
-import _ from 'underscore';
import {View} from 'react-native';
-import SelectionList from '../components/SelectionList';
-import CONST from '../CONST';
-import styles from '../styles/styles';
-import Text from '../components/Text';
+import _ from 'underscore';
+import SelectionList from '@components/SelectionList';
+import Text from '@components/Text';
+import styles from '@styles/styles';
+import CONST from '@src/CONST';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/SubscriptAvatar.stories.js b/src/stories/SubscriptAvatar.stories.js
index 08941bd9c19a..9ca055aaa5d8 100644
--- a/src/stories/SubscriptAvatar.stories.js
+++ b/src/stories/SubscriptAvatar.stories.js
@@ -1,8 +1,8 @@
import React from 'react';
-import SubscriptAvatar from '../components/SubscriptAvatar';
-import * as defaultWorkspaceAvatars from '../components/Icon/WorkspaceDefaultAvatars';
-import * as defaultAvatars from '../components/Icon/DefaultAvatars';
-import CONST from '../CONST';
+import * as defaultAvatars from '@components/Icon/DefaultAvatars';
+import * as defaultWorkspaceAvatars from '@components/Icon/WorkspaceDefaultAvatars';
+import SubscriptAvatar from '@components/SubscriptAvatar';
+import CONST from '@src/CONST';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/TextInput.stories.js b/src/stories/TextInput.stories.js
index 098828c65198..dd2fcced68b0 100644
--- a/src/stories/TextInput.stories.js
+++ b/src/stories/TextInput.stories.js
@@ -1,5 +1,5 @@
import React, {useState} from 'react';
-import TextInput from '../components/TextInput';
+import TextInput from '@components/TextInput';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/stories/Tooltip.stories.js b/src/stories/Tooltip.stories.js
index e88c48fcf202..900cd6dedd76 100644
--- a/src/stories/Tooltip.stories.js
+++ b/src/stories/Tooltip.stories.js
@@ -1,5 +1,5 @@
import React from 'react';
-import Tooltip from '../components/Tooltip';
+import Tooltip from '@components/Tooltip';
/**
* We use the Component Story Format for writing stories. Follow the docs here:
diff --git a/src/styles/StyleUtils.ts b/src/styles/StyleUtils.ts
index 48100b2efb60..f58d2c9a236d 100644
--- a/src/styles/StyleUtils.ts
+++ b/src/styles/StyleUtils.ts
@@ -2,9 +2,10 @@ import {CSSProperties} from 'react';
import {Animated, DimensionValue, ImageStyle, PressableStateCallbackType, TextStyle, ViewStyle} from 'react-native';
import {EdgeInsets} from 'react-native-safe-area-context';
import {ValueOf} from 'type-fest';
-import CONST from '../CONST';
-import * as Browser from '../libs/Browser';
-import * as UserUtils from '../libs/UserUtils';
+import * as Browser from '@libs/Browser';
+import * as UserUtils from '@libs/UserUtils';
+import CONST from '@src/CONST';
+import {Transaction} from '@src/types/onyx';
import colors from './colors';
import fontFamily from './fontFamily';
import styles from './styles';
@@ -13,7 +14,6 @@ import cursor from './utilities/cursor';
import positioning from './utilities/positioning';
import spacing from './utilities/spacing';
import variables from './variables';
-import {Transaction} from '../types/onyx';
type AllStyles = ViewStyle | TextStyle | ImageStyle;
type ParsableStyle = AllStyles | ((state: PressableStateCallbackType) => AllStyles);
diff --git a/src/styles/ThemeStylesProvider.tsx b/src/styles/ThemeStylesProvider.tsx
index 4e6f91baf34a..25ce1f58b65e 100644
--- a/src/styles/ThemeStylesProvider.tsx
+++ b/src/styles/ThemeStylesProvider.tsx
@@ -1,9 +1,9 @@
/* eslint-disable react/jsx-props-no-spreading */
import React, {useMemo} from 'react';
-import useTheme from './themes/useTheme';
-import ThemeStylesContext from './ThemeStylesContext';
// TODO: Rename this to "styles" once the app is migrated to theme switching hooks and HOCs
import {stylesGenerator as stylesUntyped} from './styles';
+import useTheme from './themes/useTheme';
+import ThemeStylesContext from './ThemeStylesContext';
const styles = stylesUntyped;
diff --git a/src/styles/addOutlineWidth/index.native.ts b/src/styles/addOutlineWidth/index.native.ts
index 69e2ffaf3a5b..4384a3f811e2 100644
--- a/src/styles/addOutlineWidth/index.native.ts
+++ b/src/styles/addOutlineWidth/index.native.ts
@@ -2,7 +2,6 @@
* Native platforms don't support the "addOutlineWidth" property, so this
* function is a no-op
*/
-
import AddOutlineWidth from './types';
const addOutlineWidth: AddOutlineWidth = (obj) => obj;
diff --git a/src/styles/addOutlineWidth/index.ts b/src/styles/addOutlineWidth/index.ts
index 6fe2ecf85978..5d99e369b79a 100644
--- a/src/styles/addOutlineWidth/index.ts
+++ b/src/styles/addOutlineWidth/index.ts
@@ -2,8 +2,7 @@
* Web and desktop platforms support the "addOutlineWidth" property, so it
* can be added to the object
*/
-
-import themeDefault from '../themes/default';
+import themeDefault from '@styles/themes/default';
import AddOutlineWidth from './types';
/**
diff --git a/src/styles/animation/SpinningIndicatorAnimation.js b/src/styles/animation/SpinningIndicatorAnimation.js
index 29044f0d127a..1ae4b1518325 100644
--- a/src/styles/animation/SpinningIndicatorAnimation.js
+++ b/src/styles/animation/SpinningIndicatorAnimation.js
@@ -1,5 +1,5 @@
import {Animated, Easing} from 'react-native';
-import useNativeDriver from '../../libs/useNativeDriver';
+import useNativeDriver from '@libs/useNativeDriver';
class SpinningIndicatorAnimation {
constructor() {
diff --git a/src/styles/cardStyles/index.ts b/src/styles/cardStyles/index.ts
index 1f28ca4f4b78..b5d3c069b73a 100644
--- a/src/styles/cardStyles/index.ts
+++ b/src/styles/cardStyles/index.ts
@@ -1,4 +1,4 @@
-import positioning from '../utilities/positioning';
+import positioning from '@styles/utilities/positioning';
import GetCardStyles from './types';
/**
diff --git a/src/styles/containerComposeStyles/index.native.ts b/src/styles/containerComposeStyles/index.native.ts
index ea525dc652cf..9e1398b8176f 100644
--- a/src/styles/containerComposeStyles/index.native.ts
+++ b/src/styles/containerComposeStyles/index.native.ts
@@ -1,4 +1,4 @@
-import styles from '../styles';
+import styles from '@styles/styles';
import ContainerComposeStyles from './types';
const containerComposeStyles: ContainerComposeStyles = [styles.textInputComposeSpacing];
diff --git a/src/styles/containerComposeStyles/index.ts b/src/styles/containerComposeStyles/index.ts
index fbbf35a20818..0e40adda571e 100644
--- a/src/styles/containerComposeStyles/index.ts
+++ b/src/styles/containerComposeStyles/index.ts
@@ -1,4 +1,4 @@
-import styles from '../styles';
+import styles from '@styles/styles';
import ContainerComposeStyles from './types';
// We need to set paddingVertical = 0 on web to avoid displaying a normal pointer on some parts of compose box when not in focus
diff --git a/src/styles/editedLabelStyles/index.ts b/src/styles/editedLabelStyles/index.ts
index 5764735d0dea..339c50d8a4df 100644
--- a/src/styles/editedLabelStyles/index.ts
+++ b/src/styles/editedLabelStyles/index.ts
@@ -1,5 +1,5 @@
-import display from '../utilities/display';
-import flex from '../utilities/flex';
+import display from '@styles/utilities/display';
+import flex from '@styles/utilities/flex';
import EditedLabelStyles from './types';
const editedLabelStyles: EditedLabelStyles = {
diff --git a/src/styles/getContextMenuItemStyles/index.js b/src/styles/getContextMenuItemStyles/index.js
index 17f4b82f1290..4116ac75ce05 100644
--- a/src/styles/getContextMenuItemStyles/index.js
+++ b/src/styles/getContextMenuItemStyles/index.js
@@ -1,5 +1,5 @@
-import styles from '../styles';
-import variables from '../variables';
+import styles from '@styles/styles';
+import variables from '@styles/variables';
export default (windowWidth) => {
if (windowWidth > variables.mobileResponsiveWidthBreakpoint) {
diff --git a/src/styles/getContextMenuItemStyles/index.native.js b/src/styles/getContextMenuItemStyles/index.native.js
index aa7ed19a88d7..cbb048a68d2f 100644
--- a/src/styles/getContextMenuItemStyles/index.native.js
+++ b/src/styles/getContextMenuItemStyles/index.native.js
@@ -1,3 +1,3 @@
-import styles from '../styles';
+import styles from '@styles/styles';
export default () => [styles.popoverMenuItem];
diff --git a/src/styles/getModalStyles.ts b/src/styles/getModalStyles.ts
index d52d29568c2d..55f822693b3e 100644
--- a/src/styles/getModalStyles.ts
+++ b/src/styles/getModalStyles.ts
@@ -1,7 +1,7 @@
import {ViewStyle} from 'react-native';
import {ModalProps} from 'react-native-modal';
import {ValueOf} from 'type-fest';
-import CONST from '../CONST';
+import CONST from '@src/CONST';
import styles from './styles';
import themeColors from './themes/default';
import variables from './variables';
diff --git a/src/styles/getNavigationModalCardStyles/index.desktop.ts b/src/styles/getNavigationModalCardStyles/index.desktop.ts
index 75b5636f9bd8..9e182636ad76 100644
--- a/src/styles/getNavigationModalCardStyles/index.desktop.ts
+++ b/src/styles/getNavigationModalCardStyles/index.desktop.ts
@@ -1,4 +1,4 @@
-import positioning from '../utilities/positioning';
+import positioning from '@styles/utilities/positioning';
import GetNavigationModalCardStyles from './types';
const getNavigationModalCardStyles: GetNavigationModalCardStyles = () => ({
diff --git a/src/styles/getNavigationModalCardStyles/index.website.ts b/src/styles/getNavigationModalCardStyles/index.website.ts
index 75b5636f9bd8..9e182636ad76 100644
--- a/src/styles/getNavigationModalCardStyles/index.website.ts
+++ b/src/styles/getNavigationModalCardStyles/index.website.ts
@@ -1,4 +1,4 @@
-import positioning from '../utilities/positioning';
+import positioning from '@styles/utilities/positioning';
import GetNavigationModalCardStyles from './types';
const getNavigationModalCardStyles: GetNavigationModalCardStyles = () => ({
diff --git a/src/styles/getPopOverVerticalOffset/index.desktop.ts b/src/styles/getPopOverVerticalOffset/index.desktop.ts
index d7c02f95b169..3caab6057a4b 100644
--- a/src/styles/getPopOverVerticalOffset/index.desktop.ts
+++ b/src/styles/getPopOverVerticalOffset/index.desktop.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import GetPopOverVerticalOffset from './types';
/** Adds the header padding with vertical offset on desktop */
diff --git a/src/styles/optionRowStyles/index.native.ts b/src/styles/optionRowStyles/index.native.ts
index 9c13fdd082a4..6198def8219a 100644
--- a/src/styles/optionRowStyles/index.native.ts
+++ b/src/styles/optionRowStyles/index.native.ts
@@ -1,4 +1,4 @@
-import styles from '../styles';
+import styles from '@styles/styles';
import CompactContentContainerStyles from './types';
/**
diff --git a/src/styles/optionRowStyles/index.ts b/src/styles/optionRowStyles/index.ts
index 975f4243842e..d0351be24553 100644
--- a/src/styles/optionRowStyles/index.ts
+++ b/src/styles/optionRowStyles/index.ts
@@ -1,5 +1,5 @@
+import styles from '@styles/styles';
import CompactContentContainerStyles from './types';
-import styles from '../styles';
const compactContentContainerStyles: CompactContentContainerStyles = styles.alignItemsBaseline;
diff --git a/src/styles/styles.ts b/src/styles/styles.ts
index 55b4223945e9..589c3756042f 100644
--- a/src/styles/styles.ts
+++ b/src/styles/styles.ts
@@ -6,10 +6,11 @@ import {AnimatableNumericValue, Animated, ImageStyle, TextStyle, ViewStyle} from
import {CustomAnimation} from 'react-native-animatable';
import {PickerStyle} from 'react-native-picker-select';
import {MixedStyleDeclaration, MixedStyleRecord} from 'react-native-render-html';
-import CONST from '../CONST';
-import * as Browser from '../libs/Browser';
+import * as Browser from '@libs/Browser';
+import CONST from '@src/CONST';
import addOutlineWidth from './addOutlineWidth';
import codeStyles from './codeStyles';
+import colors from './colors';
import fontFamily from './fontFamily';
import fontWeightBold from './fontWeight/bold';
import getPopOverVerticalOffset from './getPopOverVerticalOffset';
@@ -19,14 +20,16 @@ import pointerEventsAuto from './pointerEventsAuto';
import pointerEventsNone from './pointerEventsNone';
import defaultTheme from './themes/default';
import {ThemeDefault} from './themes/types';
+import borders from './utilities/borders';
import cursor from './utilities/cursor';
import display from './utilities/display';
import flex from './utilities/flex';
+import objectFit from './utilities/objectFit';
import overflow from './utilities/overflow';
import positioning from './utilities/positioning';
import sizing from './utilities/sizing';
import spacing from './utilities/spacing';
-import borders from './utilities/borders';
+import textDecorationLine from './utilities/textDecorationLine';
import textUnderline from './utilities/textUnderline';
import userSelect from './utilities/userSelect';
import visibility from './utilities/visibility';
@@ -34,8 +37,6 @@ import whiteSpace from './utilities/whiteSpace';
import wordBreak from './utilities/wordBreak';
import writingDirection from './utilities/writingDirection';
import variables from './variables';
-import colors from './colors';
-import objectFit from './utilities/objectFit';
type AnchorPosition = {
horizontal: number;
@@ -227,6 +228,7 @@ const styles = (theme: ThemeDefault) =>
...userSelect,
...textUnderline,
...objectFit,
+ ...textDecorationLine,
autoCompleteSuggestionsContainer: {
backgroundColor: theme.appBG,
@@ -246,6 +248,11 @@ const styles = (theme: ThemeDefault) =>
alignItems: 'center',
},
+ rtlTextRenderForSafari: {
+ textAlign: 'left',
+ ...writingDirection.ltr,
+ },
+
emojiSuggestionsEmoji: {
fontSize: variables.fontSizeMedium,
width: 51,
@@ -480,7 +487,9 @@ const styles = (theme: ThemeDefault) =>
borderRadius: variables.buttonBorderRadius,
minHeight: variables.componentSizeLarge,
justifyContent: 'center',
+ alignItems: 'center',
...spacing.ph3,
+ ...spacing.pv0,
},
buttonContainer: {
@@ -507,18 +516,14 @@ const styles = (theme: ThemeDefault) =>
buttonSmall: {
borderRadius: variables.buttonBorderRadius,
minHeight: variables.componentSizeSmall,
- paddingTop: 4,
paddingHorizontal: 14,
- paddingBottom: 4,
backgroundColor: theme.buttonDefaultBG,
},
buttonMedium: {
borderRadius: variables.buttonBorderRadius,
minHeight: variables.componentSizeNormal,
- paddingTop: 12,
paddingRight: 16,
- paddingBottom: 12,
paddingLeft: 16,
backgroundColor: theme.buttonDefaultBG,
},
@@ -526,9 +531,7 @@ const styles = (theme: ThemeDefault) =>
buttonLarge: {
borderRadius: variables.buttonBorderRadius,
minHeight: variables.componentSizeLarge,
- paddingTop: 8,
paddingRight: 10,
- paddingBottom: 8,
paddingLeft: 10,
backgroundColor: theme.buttonDefaultBG,
},
@@ -609,7 +612,6 @@ const styles = (theme: ThemeDefault) =>
},
buttonCTA: {
- paddingVertical: 6,
...spacing.mh4,
},
@@ -1643,6 +1645,10 @@ const styles = (theme: ThemeDefault) =>
width: 18,
},
+ chatContentScrollViewWithHeaderLoader: {
+ paddingTop: CONST.CHAT_HEADER_LOADER_HEIGHT,
+ },
+
chatContentScrollView: {
flexGrow: 1,
justifyContent: 'flex-start',
@@ -2894,16 +2900,6 @@ const styles = (theme: ThemeDefault) =>
width: variables.sideBarWidth - 68,
},
- cardOverlay: {
- backgroundColor: theme.overlay,
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- opacity: variables.overlayOpacity,
- },
-
shortTermsBorder: {
borderWidth: 1,
borderColor: theme.border,
@@ -3159,7 +3155,7 @@ const styles = (theme: ThemeDefault) =>
paymentMethod: {
paddingHorizontal: 20,
- height: 64,
+ height: variables.optionRowHeight,
},
archivedReportFooter: {
@@ -3903,6 +3899,15 @@ const styles = (theme: ThemeDefault) =>
width: '100%',
},
+ chatBottomLoader: {
+ position: 'absolute',
+ top: 0,
+ bottom: 0,
+ left: 0,
+ right: 0,
+ height: CONST.CHAT_HEADER_LOADER_HEIGHT,
+ },
+
videoContainer: {
...flex.flex1,
...flex.alignItemsCenter,
diff --git a/src/styles/themes/ThemeProvider.js b/src/styles/themes/ThemeProvider.js
index f4601712a0bc..58d0baedbe06 100644
--- a/src/styles/themes/ThemeProvider.js
+++ b/src/styles/themes/ThemeProvider.js
@@ -1,12 +1,11 @@
/* eslint-disable react/jsx-props-no-spreading */
-import React, {useMemo} from 'react';
import PropTypes from 'prop-types';
-import ThemeContext from './ThemeContext';
-import useThemePreference from './useThemePreference';
-import CONST from '../../CONST';
-
+import React, {useMemo} from 'react';
+import CONST from '@src/CONST';
// Going to eventually import the light theme here too
import darkTheme from './default';
+import ThemeContext from './ThemeContext';
+import useThemePreference from './useThemePreference';
const propTypes = {
/** Rendered child component */
diff --git a/src/styles/themes/default.ts b/src/styles/themes/default.ts
index b46a7aea97c6..98ff8773fb51 100644
--- a/src/styles/themes/default.ts
+++ b/src/styles/themes/default.ts
@@ -1,5 +1,5 @@
-import SCREENS from '../../SCREENS';
-import colors from '../colors';
+import colors from '@styles/colors';
+import SCREENS from '@src/SCREENS';
import type {ThemeBase} from './types';
const darkTheme = {
diff --git a/src/styles/themes/light.ts b/src/styles/themes/light.ts
index 6e8a89a7b9d2..624c7df0caa8 100644
--- a/src/styles/themes/light.ts
+++ b/src/styles/themes/light.ts
@@ -1,5 +1,5 @@
-import SCREENS from '../../SCREENS';
-import colors from '../colors';
+import colors from '@styles/colors';
+import SCREENS from '@src/SCREENS';
import type {ThemeDefault} from './types';
const lightTheme = {
diff --git a/src/styles/themes/types.ts b/src/styles/themes/types.ts
index 40b8da361654..59e8001d29fe 100644
--- a/src/styles/themes/types.ts
+++ b/src/styles/themes/types.ts
@@ -1,4 +1,4 @@
-import DeepRecord from '../../types/utils/DeepRecord';
+import DeepRecord from '@src/types/utils/DeepRecord';
import defaultTheme from './default';
type ThemeBase = DeepRecord;
diff --git a/src/styles/themes/useThemePreference.js b/src/styles/themes/useThemePreference.js
index 579e9dc97c69..8c26ad931d6d 100644
--- a/src/styles/themes/useThemePreference.js
+++ b/src/styles/themes/useThemePreference.js
@@ -1,7 +1,7 @@
-import {useState, useEffect, useContext} from 'react';
+import {useContext, useEffect, useState} from 'react';
import {Appearance} from 'react-native';
-import CONST from '../../CONST';
-import {PreferredThemeContext} from '../../components/OnyxProvider';
+import {PreferredThemeContext} from '@components/OnyxProvider';
+import CONST from '@src/CONST';
function useThemePreference() {
const [themePreference, setThemePreference] = useState(CONST.THEME.DEFAULT);
diff --git a/src/styles/utilities/spacing.ts b/src/styles/utilities/spacing.ts
index c66b7cbd5250..f88692bcc85b 100644
--- a/src/styles/utilities/spacing.ts
+++ b/src/styles/utilities/spacing.ts
@@ -155,6 +155,10 @@ export default {
marginLeft: 32,
},
+ ml9: {
+ marginLeft: 36,
+ },
+
ml10: {
marginLeft: 40,
},
diff --git a/src/styles/utilities/textDecorationLine.ts b/src/styles/utilities/textDecorationLine.ts
new file mode 100644
index 000000000000..02e7db41e10a
--- /dev/null
+++ b/src/styles/utilities/textDecorationLine.ts
@@ -0,0 +1,8 @@
+import {TextStyle} from 'react-native';
+
+export default {
+ lineThrough: {
+ textDecorationLine: 'line-through',
+ textDecorationStyle: 'solid',
+ },
+} satisfies Record;
diff --git a/src/styles/utilities/writingDirection.ts b/src/styles/utilities/writingDirection.ts
index 1d9a32122373..f3f249796047 100644
--- a/src/styles/utilities/writingDirection.ts
+++ b/src/styles/utilities/writingDirection.ts
@@ -1,4 +1,5 @@
import {TextStyle} from 'react-native';
+
/**
* Writing direction utility styles.
* Note: writingDirection isn't supported on Android. Unicode controls are being used for Android
diff --git a/src/types/modules/react-native-key-command.d.ts b/src/types/modules/react-native-key-command.d.ts
index f93204891e84..4c7f07bd6d7e 100644
--- a/src/types/modules/react-native-key-command.d.ts
+++ b/src/types/modules/react-native-key-command.d.ts
@@ -1,29 +1,31 @@
+/* eslint-disable @typescript-eslint/naming-convention */
declare module 'react-native-key-command' {
- declare const constants = {
- keyInputDownArrow: 'keyInputDownArrow',
- keyInputEscape: 'keyInputEscape',
- keyInputLeftArrow: 'keyInputLeftArrow',
- keyInputRightArrow: 'keyInputRightArrow',
- keyInputUpArrow: 'keyInputUpArrow',
- keyInputEnter: 'keyInputEnter',
- keyModifierCapsLock: 'keyModifierCapsLock',
- keyModifierCommand: 'keyModifierCommand',
- keyModifierControl: 'keyModifierControl',
- keyModifierControlCommand: 'keyModifierControlCommand',
- keyModifierControlOption: 'keyModifierControlOption',
- keyModifierControlOptionCommand: 'keyModifierControlOptionCommand',
- keyModifierNumericPad: 'keyModifierNumericPad',
- keyModifierOption: 'keyModifierOption',
- keyModifierOptionCommand: 'keyModifierOptionCommand',
- keyModifierShift: 'keyModifierShift',
- keyModifierShiftCommand: 'keyModifierShiftCommand',
- keyModifierShiftControl: 'keyModifierShiftControl',
- keyModifierAlternate: 'keyModifierAlternate',
- } as const;
+ // eslint-disable-next-line no-restricted-syntax
+ enum constants {
+ keyInputDownArrow = 'keyInputDownArrow',
+ keyInputEscape = 'keyInputEscape',
+ keyInputLeftArrow = 'keyInputLeftArrow',
+ keyInputRightArrow = 'keyInputRightArrow',
+ keyInputUpArrow = 'keyInputUpArrow',
+ keyInputEnter = 'keyInputEnter',
+ keyModifierCapsLock = 'keyModifierCapsLock',
+ keyModifierCommand = 'keyModifierCommand',
+ keyModifierControl = 'keyModifierControl',
+ keyModifierControlCommand = 'keyModifierControlCommand',
+ keyModifierControlOption = 'keyModifierControlOption',
+ keyModifierControlOptionCommand = 'keyModifierControlOptionCommand',
+ keyModifierNumericPad = 'keyModifierNumericPad',
+ keyModifierOption = 'keyModifierOption',
+ keyModifierOptionCommand = 'keyModifierOptionCommand',
+ keyModifierShift = 'keyModifierShift',
+ keyModifierShiftCommand = 'keyModifierShiftCommand',
+ keyModifierShiftControl = 'keyModifierShiftControl',
+ keyModifierAlternate = 'keyModifierAlternate',
+ }
- type KeyCommand = {input: string; modifierFlags: string};
+ type KeyCommand = {input: string; modifierFlags?: string};
- declare function addListener(keyCommand: KeyCommand, callback: (keycommandEvent: KeyCommand, event: Event) => void): () => void;
+ declare function addListener(keyCommand: KeyCommand, callback: (keycommandEvent: KeyCommand, event: KeyboardEvent) => void): () => void;
// eslint-disable-next-line import/prefer-default-export
export {constants, addListener};
diff --git a/src/types/modules/react-native-onyx.d.ts b/src/types/modules/react-native-onyx.d.ts
index 4979f8fd0dbb..d603b9f93ae8 100644
--- a/src/types/modules/react-native-onyx.d.ts
+++ b/src/types/modules/react-native-onyx.d.ts
@@ -1,4 +1,4 @@
-import {OnyxKey, OnyxCollectionKey, OnyxValues} from '../../ONYXKEYS';
+import {OnyxCollectionKey, OnyxKey, OnyxValues} from '@src/ONYXKEYS';
declare module 'react-native-onyx' {
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
diff --git a/src/types/modules/react-native.d.ts b/src/types/modules/react-native.d.ts
index 0659cc4e4b4a..a816fc77625b 100644
--- a/src/types/modules/react-native.d.ts
+++ b/src/types/modules/react-native.d.ts
@@ -1,9 +1,11 @@
/* eslint-disable @typescript-eslint/naming-convention */
+
/* eslint-disable @typescript-eslint/no-empty-interface */
+
/* eslint-disable @typescript-eslint/consistent-type-definitions */
import {CSSProperties, FocusEventHandler, KeyboardEventHandler, MouseEventHandler, PointerEventHandler, UIEventHandler, WheelEventHandler} from 'react';
import 'react-native';
-import {BootSplashModule} from '../../libs/BootSplash/types';
+import {BootSplashModule} from '@libs/BootSplash/types';
declare module 'react-native' {
// <------ REACT NATIVE WEB (0.19.0) ------>
diff --git a/src/types/onyx/Account.ts b/src/types/onyx/Account.ts
index 85b0c2359702..c338924bae55 100644
--- a/src/types/onyx/Account.ts
+++ b/src/types/onyx/Account.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
type TwoFactorAuthStep = ValueOf | '';
diff --git a/src/types/onyx/BankAccount.ts b/src/types/onyx/BankAccount.ts
index 58d9654f0c6f..4a7b6dac7387 100644
--- a/src/types/onyx/BankAccount.ts
+++ b/src/types/onyx/BankAccount.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import AccountData from './AccountData';
import * as OnyxCommon from './OnyxCommon';
diff --git a/src/types/onyx/Beta.ts b/src/types/onyx/Beta.ts
index d40d05a9ed3d..9216946499e8 100644
--- a/src/types/onyx/Beta.ts
+++ b/src/types/onyx/Beta.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
type Beta = ValueOf;
diff --git a/src/types/onyx/Card.ts b/src/types/onyx/Card.ts
index 2e013957f56f..ae4e86212a00 100644
--- a/src/types/onyx/Card.ts
+++ b/src/types/onyx/Card.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
type Card = {
@@ -19,4 +19,19 @@ type Card = {
isLoading?: boolean;
};
+type TCardDetails = {
+ pan: string;
+ expiration: string;
+ cvv: string;
+ address: {
+ street: string;
+ street2: string;
+ city: string;
+ state: string;
+ zip: string;
+ country: string;
+ };
+};
+
export default Card;
+export type {TCardDetails};
diff --git a/src/types/onyx/Fund.ts b/src/types/onyx/Fund.ts
index e27cc0e20e0e..4e6cbc695a8d 100644
--- a/src/types/onyx/Fund.ts
+++ b/src/types/onyx/Fund.ts
@@ -1,4 +1,4 @@
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
type AdditionalData = {
diff --git a/src/types/onyx/OnyxCommon.ts b/src/types/onyx/OnyxCommon.ts
index db82edcb98ff..bafd5e8cbbf0 100644
--- a/src/types/onyx/OnyxCommon.ts
+++ b/src/types/onyx/OnyxCommon.ts
@@ -1,6 +1,6 @@
-import {ValueOf} from 'type-fest';
import * as React from 'react';
-import CONST from '../../CONST';
+import {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
type PendingAction = ValueOf;
diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts
index 26ccb59f4f46..014cd67a9a2a 100644
--- a/src/types/onyx/OriginalMessage.ts
+++ b/src/types/onyx/OriginalMessage.ts
@@ -1,6 +1,6 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
-import DeepValueOf from '../utils/DeepValueOf';
+import CONST from '@src/CONST';
+import DeepValueOf from '@src/types/utils/DeepValueOf';
type ActionName = DeepValueOf;
@@ -145,7 +145,18 @@ type OriginalMessageReportPreview = {
type OriginalMessagePolicyChangeLog = {
actionName: ValueOf;
- originalMessage: unknown;
+ originalMessage: {
+ targetAccountIDs?: number[];
+ roomName?: string;
+ };
+};
+
+type OriginalMessageRoomChangeLog = {
+ actionName: ValueOf;
+ originalMessage: {
+ targetAccountIDs?: number[];
+ roomName?: string;
+ };
};
type OriginalMessagePolicyTask = {
@@ -177,6 +188,7 @@ type OriginalMessage =
| OriginalMessageRenamed
| OriginalMessageChronosOOOList
| OriginalMessageReportPreview
+ | OriginalMessageRoomChangeLog
| OriginalMessagePolicyChangeLog
| OriginalMessagePolicyTask
| OriginalMessageModifiedExpense
diff --git a/src/types/onyx/PaymentMethod.ts b/src/types/onyx/PaymentMethod.ts
index 85f3655f49e8..4a9722911bf9 100644
--- a/src/types/onyx/PaymentMethod.ts
+++ b/src/types/onyx/PaymentMethod.ts
@@ -1,6 +1,6 @@
-import {SvgProps} from 'react-native-svg';
import {CSSProperties} from 'react';
import {ViewStyle} from 'react-native';
+import {SvgProps} from 'react-native-svg';
import BankAccount from './BankAccount';
import Fund from './Fund';
diff --git a/src/types/onyx/PersonalDetails.ts b/src/types/onyx/PersonalDetails.ts
index 201273beac63..0cd264802128 100644
--- a/src/types/onyx/PersonalDetails.ts
+++ b/src/types/onyx/PersonalDetails.ts
@@ -42,6 +42,9 @@ type PersonalDetails = {
/** Timezone of the current user from their personal details */
timezone?: Timezone;
+
+ /** Status of the current user from their personal details */
+ status?: string;
};
export type {Timezone};
diff --git a/src/types/onyx/PlaidData.ts b/src/types/onyx/PlaidData.ts
index a4a6d8e6fe8c..28a1cb324bcb 100644
--- a/src/types/onyx/PlaidData.ts
+++ b/src/types/onyx/PlaidData.ts
@@ -1,5 +1,5 @@
-import PlaidBankAccount from './PlaidBankAccount';
import * as OnyxCommon from './OnyxCommon';
+import PlaidBankAccount from './PlaidBankAccount';
type PlaidData = {
/** Name of the bank */
diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts
index e4d77b150a7c..6b115bf0609f 100644
--- a/src/types/onyx/Policy.ts
+++ b/src/types/onyx/Policy.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
type Policy = {
diff --git a/src/types/onyx/PolicyMember.ts b/src/types/onyx/PolicyMember.ts
index 055465020c36..60836b276ea0 100644
--- a/src/types/onyx/PolicyMember.ts
+++ b/src/types/onyx/PolicyMember.ts
@@ -14,4 +14,7 @@ type PolicyMember = {
pendingAction?: OnyxCommon.PendingAction;
};
+type PolicyMembers = Record;
+
export default PolicyMember;
+export type {PolicyMembers};
diff --git a/src/types/onyx/PolicyTag.ts b/src/types/onyx/PolicyTag.ts
index fe6bee3a1f31..7807dcc00433 100644
--- a/src/types/onyx/PolicyTag.ts
+++ b/src/types/onyx/PolicyTag.ts
@@ -10,4 +10,7 @@ type PolicyTag = {
'GL Code': string;
};
+type PolicyTags = Record;
+
export default PolicyTag;
+export type {PolicyTags};
diff --git a/src/types/onyx/RecentWaypoint.ts b/src/types/onyx/RecentWaypoint.ts
index 79aded8ede98..097aed3be916 100644
--- a/src/types/onyx/RecentWaypoint.ts
+++ b/src/types/onyx/RecentWaypoint.ts
@@ -1,4 +1,7 @@
type RecentWaypoint = {
+ /** The name associated with the address of the waypoint */
+ name?: string;
+
/** The full address of the waypoint */
address: string;
diff --git a/src/types/onyx/ReimbursementAccount.ts b/src/types/onyx/ReimbursementAccount.ts
index fc46c9aa3132..75954983371e 100644
--- a/src/types/onyx/ReimbursementAccount.ts
+++ b/src/types/onyx/ReimbursementAccount.ts
@@ -1,6 +1,6 @@
import {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
-import CONST from '../../CONST';
type BankAccountStep = ValueOf;
diff --git a/src/types/onyx/Report.ts b/src/types/onyx/Report.ts
index 8587cf9b7cd5..6fe9b5fd5099 100644
--- a/src/types/onyx/Report.ts
+++ b/src/types/onyx/Report.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
type Report = {
@@ -72,7 +72,25 @@ type Report = {
participantAccountIDs?: number[];
total?: number;
currency?: string;
+
+ /** Whether the report is waiting on a bank account */
+ isWaitingOnBankAccount?: boolean;
+
+ /** Whether the last message was deleted */
+ isLastMessageDeletedParentAction?: boolean;
+
+ /** The ID of the IOU report */
+ iouReportID?: string;
+
+ /** Total amount of money owed for IOU report */
+ iouReportAmount?: number;
+
+ /** Pending fields for the report */
+ pendingFields?: Record;
+
+ /** The ID of the preexisting report (it is possible that we optimistically created a Report for which a report already exists) */
preexistingReportID?: string;
+
/** If the report contains nonreimbursable expenses, send the nonreimbursable total */
nonReimbursableTotal?: number;
};
diff --git a/src/types/onyx/ReportAction.ts b/src/types/onyx/ReportAction.ts
index fbe4c02c4072..19908273ad3d 100644
--- a/src/types/onyx/ReportAction.ts
+++ b/src/types/onyx/ReportAction.ts
@@ -75,9 +75,6 @@ type ReportActionBase = {
/** Whether we have received a response back from the server */
isLoading?: boolean;
- /** Error message that's come back from the server. */
- error?: string;
-
/** accountIDs of the people to which the whisper was sent to (if any). Returns empty array if it is not a whisper */
whisperedToAccountIDs?: number[];
diff --git a/src/types/onyx/ReportActionsDrafts.ts b/src/types/onyx/ReportActionsDrafts.ts
new file mode 100644
index 000000000000..e40007b6b47a
--- /dev/null
+++ b/src/types/onyx/ReportActionsDrafts.ts
@@ -0,0 +1,3 @@
+type ReportActionsDrafts = Record;
+
+export default ReportActionsDrafts;
diff --git a/src/types/onyx/ReportMetadata.ts b/src/types/onyx/ReportMetadata.ts
index 3e389c8cff4f..8c13e0f127b8 100644
--- a/src/types/onyx/ReportMetadata.ts
+++ b/src/types/onyx/ReportMetadata.ts
@@ -1,9 +1,12 @@
type ReportMetadata = {
- /** Are we loading more report actions? */
- isLoadingMoreReportActions?: boolean;
+ /** Are we loading newer report actions? */
+ isLoadingNewerReportActions?: boolean;
+
+ /** Are we loading older report actions? */
+ isLoadingOlderReportActions?: boolean;
/** Flag to check if the report actions data are loading */
- isLoadingReportActions?: boolean;
+ isLoadingInitialReportActions?: boolean;
};
export default ReportMetadata;
diff --git a/src/types/onyx/Session.ts b/src/types/onyx/Session.ts
index 606723f17b82..faaa493b1286 100644
--- a/src/types/onyx/Session.ts
+++ b/src/types/onyx/Session.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
type AutoAuthState = ValueOf;
diff --git a/src/types/onyx/Transaction.ts b/src/types/onyx/Transaction.ts
index 21be3c49497e..de5f2eec9f9d 100644
--- a/src/types/onyx/Transaction.ts
+++ b/src/types/onyx/Transaction.ts
@@ -1,9 +1,12 @@
import {ValueOf} from 'type-fest';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
-import CONST from '../../CONST';
import RecentWaypoint from './RecentWaypoint';
type Waypoint = {
+ /** The name associated with the address of the waypoint */
+ name?: string;
+
/** The full address of the waypoint */
address?: string;
diff --git a/src/types/onyx/UserWallet.ts b/src/types/onyx/UserWallet.ts
index aae662f62b6f..501e05a31ad0 100644
--- a/src/types/onyx/UserWallet.ts
+++ b/src/types/onyx/UserWallet.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
type WalletLinkedAccountType = 'debitCard' | 'bankAccount';
diff --git a/src/types/onyx/WalletTransfer.ts b/src/types/onyx/WalletTransfer.ts
index 18b223a0b1ef..e1b1468d6536 100644
--- a/src/types/onyx/WalletTransfer.ts
+++ b/src/types/onyx/WalletTransfer.ts
@@ -1,5 +1,5 @@
import {ValueOf} from 'type-fest';
-import CONST from '../../CONST';
+import CONST from '@src/CONST';
import * as OnyxCommon from './OnyxCommon';
import PaymentMethod from './PaymentMethod';
diff --git a/src/types/onyx/index.ts b/src/types/onyx/index.ts
index 4603c4579343..93a19b39aad3 100644
--- a/src/types/onyx/index.ts
+++ b/src/types/onyx/index.ts
@@ -1,52 +1,53 @@
import Account from './Account';
-import Request from './Request';
+import AccountData from './AccountData';
+import BankAccount from './BankAccount';
+import Beta from './Beta';
+import BlockedFromConcierge from './BlockedFromConcierge';
+import Card from './Card';
import Credentials from './Credentials';
+import Currency from './Currency';
+import CustomStatusDraft from './CustomStatusDraft';
+import Download from './Download';
+import Form, {AddDebitCardForm} from './Form';
+import FrequentlyUsedEmoji from './FrequentlyUsedEmoji';
+import Fund from './Fund';
import IOU from './IOU';
+import Login from './Login';
+import MapboxAccessToken from './MapboxAccessToken';
import Modal from './Modal';
import Network from './Network';
-import CustomStatusDraft from './CustomStatusDraft';
+import {OnyxUpdateEvent, OnyxUpdatesFromServer} from './OnyxUpdatesFromServer';
+import PersonalBankAccount from './PersonalBankAccount';
import PersonalDetails from './PersonalDetails';
-import PrivatePersonalDetails from './PrivatePersonalDetails';
-import Task from './Task';
-import Currency from './Currency';
-import ScreenShareRequest from './ScreenShareRequest';
-import User from './User';
-import Login from './Login';
-import Session from './Session';
-import Beta from './Beta';
-import BlockedFromConcierge from './BlockedFromConcierge';
import PlaidData from './PlaidData';
-import UserWallet from './UserWallet';
-import WalletOnfido from './WalletOnfido';
-import WalletAdditionalDetails from './WalletAdditionalDetails';
-import WalletTerms from './WalletTerms';
-import BankAccount from './BankAccount';
-import Card from './Card';
-import Fund from './Fund';
-import WalletStatement from './WalletStatement';
-import PersonalBankAccount from './PersonalBankAccount';
-import FrequentlyUsedEmoji from './FrequentlyUsedEmoji';
-import ReimbursementAccount from './ReimbursementAccount';
-import ReimbursementAccountDraft from './ReimbursementAccountDraft';
-import WalletTransfer from './WalletTransfer';
-import MapboxAccessToken from './MapboxAccessToken';
-import {OnyxUpdatesFromServer, OnyxUpdateEvent} from './OnyxUpdatesFromServer';
-import Download from './Download';
-import PolicyMember from './PolicyMember';
import Policy from './Policy';
import PolicyCategory from './PolicyCategory';
+import PolicyMember, {PolicyMembers} from './PolicyMember';
+import PolicyTag, {PolicyTags} from './PolicyTag';
+import PrivatePersonalDetails from './PrivatePersonalDetails';
+import RecentlyUsedCategories from './RecentlyUsedCategories';
+import RecentlyUsedTags from './RecentlyUsedTags';
+import RecentWaypoint from './RecentWaypoint';
+import ReimbursementAccount from './ReimbursementAccount';
+import ReimbursementAccountDraft from './ReimbursementAccountDraft';
import Report from './Report';
-import ReportMetadata from './ReportMetadata';
import ReportAction, {ReportActions} from './ReportAction';
import ReportActionReactions from './ReportActionReactions';
+import ReportActionsDrafts from './ReportActionsDrafts';
+import ReportMetadata from './ReportMetadata';
+import Request from './Request';
+import ScreenShareRequest from './ScreenShareRequest';
import SecurityGroup from './SecurityGroup';
+import Session from './Session';
+import Task from './Task';
import Transaction from './Transaction';
-import Form, {AddDebitCardForm} from './Form';
-import RecentWaypoint from './RecentWaypoint';
-import RecentlyUsedCategories from './RecentlyUsedCategories';
-import RecentlyUsedTags from './RecentlyUsedTags';
-import PolicyTag from './PolicyTag';
-import AccountData from './AccountData';
+import User from './User';
+import UserWallet from './UserWallet';
+import WalletAdditionalDetails from './WalletAdditionalDetails';
+import WalletOnfido from './WalletOnfido';
+import WalletStatement from './WalletStatement';
+import WalletTerms from './WalletTerms';
+import WalletTransfer from './WalletTransfer';
export type {
Account,
@@ -89,6 +90,7 @@ export type {
ReportMetadata,
ReportAction,
ReportActions,
+ ReportActionsDrafts,
ReportActionReactions,
SecurityGroup,
Transaction,
@@ -100,5 +102,7 @@ export type {
RecentlyUsedCategories,
RecentlyUsedTags,
PolicyTag,
+ PolicyTags,
+ PolicyMembers,
AccountData,
};
diff --git a/tests/actions/IOUTest.js b/tests/actions/IOUTest.js
index 71a5558e921e..2c6b94a2d7d5 100644
--- a/tests/actions/IOUTest.js
+++ b/tests/actions/IOUTest.js
@@ -1,24 +1,24 @@
-import _ from 'underscore';
import Onyx from 'react-native-onyx';
+import _ from 'underscore';
import CONST from '../../src/CONST';
-import ONYXKEYS from '../../src/ONYXKEYS';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import * as IOU from '../../src/libs/actions/IOU';
-import * as TestHelper from '../utils/TestHelper';
-import DateUtils from '../../src/libs/DateUtils';
-import * as NumberUtils from '../../src/libs/NumberUtils';
-import * as ReportActions from '../../src/libs/actions/ReportActions';
-import * as ReportUtils from '../../src/libs/ReportUtils';
-import * as Report from '../../src/libs/actions/Report';
import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager';
-import waitForNetworkPromises from '../utils/waitForNetworkPromises';
-import * as ReportActionsUtils from '../../src/libs/ReportActionsUtils';
import * as PolicyActions from '../../src/libs/actions/Policy';
-import * as PersonalDetailsUtils from '../../src/libs/PersonalDetailsUtils';
+import * as Report from '../../src/libs/actions/Report';
+import * as ReportActions from '../../src/libs/actions/ReportActions';
import * as User from '../../src/libs/actions/User';
-import PusherHelper from '../utils/PusherHelper';
+import DateUtils from '../../src/libs/DateUtils';
import Navigation from '../../src/libs/Navigation/Navigation';
+import * as NumberUtils from '../../src/libs/NumberUtils';
+import * as PersonalDetailsUtils from '../../src/libs/PersonalDetailsUtils';
+import * as ReportActionsUtils from '../../src/libs/ReportActionsUtils';
+import * as ReportUtils from '../../src/libs/ReportUtils';
+import ONYXKEYS from '../../src/ONYXKEYS';
import ROUTES from '../../src/ROUTES';
+import PusherHelper from '../utils/PusherHelper';
+import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import waitForNetworkPromises from '../utils/waitForNetworkPromises';
jest.mock('../../src/libs/Navigation/Navigation', () => ({
navigate: jest.fn(),
@@ -107,7 +107,7 @@ describe('actions/IOU', () => {
iouAction = iouActions[0];
// The CREATED action should not be created after the IOU action
- expect(Date.parse(createdAction.created)).toBeLessThanOrEqual(Date.parse(iouAction.created));
+ expect(Date.parse(createdAction.created)).toBeLessThan(Date.parse(iouAction.created));
// The IOUReportID should be correct
expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID);
@@ -214,6 +214,7 @@ describe('actions/IOU', () => {
};
let iouReportID;
let iouAction;
+ let iouCreatedAction;
let transactionID;
fetch.pause();
return Onyx.set(`${ONYXKEYS.COLLECTION.REPORT}${chatReport.reportID}`, chatReport)
@@ -262,10 +263,11 @@ describe('actions/IOU', () => {
// The chat report should have a CREATED and an IOU action
expect(_.size(allIOUReportActions)).toBe(2);
+ iouCreatedAction = _.find(allIOUReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED);
iouAction = _.find(allIOUReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU);
// The CREATED action should not be created after the IOU action
- expect(Date.parse(createdAction.created)).toBeLessThanOrEqual(Date.parse(iouAction.created));
+ expect(Date.parse(iouCreatedAction.created)).toBeLessThan(Date.parse(iouAction.created));
// The IOUReportID should be correct
expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID);
@@ -599,7 +601,7 @@ describe('actions/IOU', () => {
iouAction = iouActions[0];
// The CREATED action should not be created after the IOU action
- expect(Date.parse(createdAction.created)).toBeLessThanOrEqual(Date.parse(iouAction.created));
+ expect(Date.parse(createdAction.created)).toBeLessThan(Date.parse(iouAction.created));
// The IOUReportID should be correct
expect(iouAction.originalMessage.IOUReportID).toBe(iouReportID);
@@ -866,9 +868,11 @@ describe('actions/IOU', () => {
let carlosIOUReport;
let carlosIOUAction;
+ let carlosIOUCreatedAction;
let carlosTransaction;
let julesIOUAction;
+ let julesIOUCreatedAction;
let julesTransaction;
let vitChatReport;
@@ -1011,17 +1015,19 @@ describe('actions/IOU', () => {
// Carlos DM should have two reportActions – the existing CREATED action and a pending IOU action
expect(_.size(carlosReportActions)).toBe(2);
+ carlosIOUCreatedAction = _.find(carlosReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED);
carlosIOUAction = _.find(carlosReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.IOU);
expect(carlosIOUAction.pendingAction).toBe(CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD);
expect(carlosIOUAction.originalMessage.IOUReportID).toBe(carlosIOUReport.reportID);
expect(carlosIOUAction.originalMessage.amount).toBe(amount / 4);
expect(carlosIOUAction.originalMessage.comment).toBe(comment);
expect(carlosIOUAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE);
- expect(Date.parse(carlosCreatedAction.created)).toBeLessThanOrEqual(Date.parse(carlosIOUAction.created));
+ expect(Date.parse(carlosIOUCreatedAction.created)).toBeLessThan(Date.parse(carlosIOUAction.created));
// Jules DM should have three reportActions, the existing CREATED action, the existing IOU action, and a new pending IOU action
expect(_.size(julesReportActions)).toBe(3);
expect(julesReportActions[julesCreatedAction.reportActionID]).toStrictEqual(julesCreatedAction);
+ julesIOUCreatedAction = _.find(julesReportActions, (reportAction) => reportAction.actionName === CONST.REPORT.ACTIONS.TYPE.CREATED);
julesIOUAction = _.find(
julesReportActions,
(reportAction) =>
@@ -1032,7 +1038,7 @@ describe('actions/IOU', () => {
expect(julesIOUAction.originalMessage.amount).toBe(amount / 4);
expect(julesIOUAction.originalMessage.comment).toBe(comment);
expect(julesIOUAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE);
- expect(Date.parse(julesCreatedAction.created)).toBeLessThanOrEqual(Date.parse(julesIOUAction.created));
+ expect(Date.parse(julesIOUCreatedAction.created)).toBeLessThan(Date.parse(julesIOUAction.created));
// Vit DM should have two reportActions – a pending CREATED action and a pending IOU action
expect(_.size(vitReportActions)).toBe(2);
@@ -1044,7 +1050,7 @@ describe('actions/IOU', () => {
expect(vitIOUAction.originalMessage.amount).toBe(amount / 4);
expect(vitIOUAction.originalMessage.comment).toBe(comment);
expect(vitIOUAction.originalMessage.type).toBe(CONST.IOU.REPORT_ACTION_TYPE.CREATE);
- expect(Date.parse(vitCreatedAction.created)).toBeLessThanOrEqual(Date.parse(vitIOUAction.created));
+ expect(Date.parse(vitCreatedAction.created)).toBeLessThan(Date.parse(vitIOUAction.created));
// Group chat should have two reportActions – a pending CREATED action and a pending IOU action w/ type SPLIT
expect(_.size(groupReportActions)).toBe(2);
diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js
index 025c226b3fb8..a94db507637b 100644
--- a/tests/actions/ReportTest.js
+++ b/tests/actions/ReportTest.js
@@ -1,23 +1,23 @@
-import _ from 'underscore';
-import Onyx from 'react-native-onyx';
-import lodashGet from 'lodash/get';
+import {afterEach, beforeAll, beforeEach, describe, expect, it} from '@jest/globals';
import {utcToZonedTime} from 'date-fns-tz';
-import {beforeEach, beforeAll, afterEach, describe, it, expect} from '@jest/globals';
-import ONYXKEYS from '../../src/ONYXKEYS';
+import lodashGet from 'lodash/get';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
import CONST from '../../src/CONST';
-import * as Report from '../../src/libs/actions/Report';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import PusherHelper from '../utils/PusherHelper';
-import * as TestHelper from '../utils/TestHelper';
-import Log from '../../src/libs/Log';
+import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager';
import * as PersistedRequests from '../../src/libs/actions/PersistedRequests';
+import * as Report from '../../src/libs/actions/Report';
import * as User from '../../src/libs/actions/User';
-import * as ReportUtils from '../../src/libs/ReportUtils';
import DateUtils from '../../src/libs/DateUtils';
+import Log from '../../src/libs/Log';
import * as SequentialQueue from '../../src/libs/Network/SequentialQueue';
-import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager';
-import waitForNetworkPromises from '../utils/waitForNetworkPromises';
+import * as ReportUtils from '../../src/libs/ReportUtils';
+import ONYXKEYS from '../../src/ONYXKEYS';
import getIsUsingFakeTimers from '../utils/getIsUsingFakeTimers';
+import PusherHelper from '../utils/PusherHelper';
+import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import waitForNetworkPromises from '../utils/waitForNetworkPromises';
const UTC = 'UTC';
jest.mock('../../src/libs/actions/Report', () => {
diff --git a/tests/actions/SessionTest.js b/tests/actions/SessionTest.js
index 4ecb2a33b763..f7d7f8ed5835 100644
--- a/tests/actions/SessionTest.js
+++ b/tests/actions/SessionTest.js
@@ -1,17 +1,16 @@
-import Onyx from 'react-native-onyx';
import {beforeEach, jest, test} from '@jest/globals';
-import HttpUtils from '../../src/libs/HttpUtils';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import ONYXKEYS from '../../src/ONYXKEYS';
-import * as TestHelper from '../utils/TestHelper';
+import Onyx from 'react-native-onyx';
import CONST from '../../src/CONST';
-import PushNotification from '../../src/libs/Notification/PushNotification';
import * as App from '../../src/libs/actions/App';
import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager';
-
+import HttpUtils from '../../src/libs/HttpUtils';
+import PushNotification from '../../src/libs/Notification/PushNotification';
// This lib needs to be imported, but it has nothing to export since all it contains is an Onyx connection
// eslint-disable-next-line no-unused-vars
import subscribePushNotification from '../../src/libs/Notification/PushNotification/subscribePushNotification';
+import ONYXKEYS from '../../src/ONYXKEYS';
+import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
// We are mocking this method so that we can later test to see if it was called and what arguments it was called with.
// We test HttpUtils.xhr() since this means that our API command turned into a network request and isn't only queued.
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) => {
diff --git a/tests/e2e/config.js b/tests/e2e/config.js
index 3b1856ab8ad8..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',
@@ -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
diff --git a/tests/perf-test/ReportActionsList.perf-test.js b/tests/perf-test/ReportActionsList.perf-test.js
index 4d83cc435636..f4dcd969923f 100644
--- a/tests/perf-test/ReportActionsList.perf-test.js
+++ b/tests/perf-test/ReportActionsList.perf-test.js
@@ -1,32 +1,40 @@
-import {measurePerformance} from 'reassure';
+import {fireEvent, screen} from '@testing-library/react-native';
import Onyx from 'react-native-onyx';
-import {screen, fireEvent} from '@testing-library/react-native';
-import ReportActionsList from '../../src/pages/home/report/ReportActionsList';
+import {measurePerformance} from 'reassure';
import ComposeProviders from '../../src/components/ComposeProviders';
+import {LocaleContextProvider} from '../../src/components/LocaleContextProvider';
import OnyxProvider from '../../src/components/OnyxProvider';
-import {ReportAttachmentsProvider} from '../../src/pages/home/report/ReportAttachmentsContext';
import {WindowDimensionsProvider} from '../../src/components/withWindowDimensions';
-import {LocaleContextProvider} from '../../src/components/LocaleContextProvider';
+import * as Localize from '../../src/libs/Localize';
+import ONYXKEYS from '../../src/ONYXKEYS';
+import ReportActionsList from '../../src/pages/home/report/ReportActionsList';
+import {ReportAttachmentsProvider} from '../../src/pages/home/report/ReportAttachmentsContext';
+import {ActionListContext, ReactionListContext} from '../../src/pages/home/ReportScreenContext';
+import variables from '../../src/styles/variables';
import * as LHNTestUtils from '../utils/LHNTestUtils';
+import PusherHelper from '../utils/PusherHelper';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
-import PusherHelper from '../utils/PusherHelper';
-import variables from '../../src/styles/variables';
-import {ActionListContext, ReactionListContext} from '../../src/pages/home/ReportScreenContext';
-import ONYXKEYS from '../../src/ONYXKEYS';
-import * as Localize from '../../src/libs/Localize';
jest.setTimeout(60000);
const mockedNavigate = jest.fn();
-jest.mock('../../src/components/withNavigationFocus', () => (Component) => (props) => (
-
-));
+jest.mock('../../src/components/withNavigationFocus', () => (Component) => {
+ function WithNavigationFocus(props) {
+ return (
+
+ );
+ }
+
+ WithNavigationFocus.displayName = 'WithNavigationFocus';
+
+ return WithNavigationFocus;
+});
jest.mock('@react-navigation/native', () => {
const actualNav = jest.requireActual('@react-navigation/native');
diff --git a/tests/perf-test/SelectionList.perf-test.js b/tests/perf-test/SelectionList.perf-test.js
index cdf9492e0ff3..f8e358db9d5c 100644
--- a/tests/perf-test/SelectionList.perf-test.js
+++ b/tests/perf-test/SelectionList.perf-test.js
@@ -1,6 +1,6 @@
+import {fireEvent} from '@testing-library/react-native';
import React, {useState} from 'react';
import {measurePerformance} from 'reassure';
-import {fireEvent} from '@testing-library/react-native';
import _ from 'underscore';
import SelectionList from '../../src/components/SelectionList';
import variables from '../../src/styles/variables';
@@ -13,13 +13,19 @@ jest.mock('../../src/hooks/useLocalize', () =>
})),
);
-jest.mock('../../src/components/withLocalize', () => (Component) => (props) => (
- ''}
- />
-));
+jest.mock('../../src/components/withLocalize', () => (Component) => {
+ function WrappedComponent(props) {
+ return (
+ ''}
+ />
+ );
+ }
+ WrappedComponent.displayName = `WrappedComponent`;
+ return WrappedComponent;
+});
jest.mock('../../src/hooks/useNetwork', () =>
jest.fn(() => ({
@@ -27,13 +33,19 @@ jest.mock('../../src/hooks/useNetwork', () =>
})),
);
-jest.mock('../../src/components/withKeyboardState', () => (Component) => (props) => (
-
-));
+jest.mock('../../src/components/withKeyboardState', () => (Component) => {
+ function WrappedComponent(props) {
+ return (
+
+ );
+ }
+ WrappedComponent.displayName = `WrappedComponent`;
+ return WrappedComponent;
+});
jest.mock('@react-navigation/native', () => ({
useFocusEffect: () => {},
diff --git a/tests/perf-test/SidebarLinks.perf-test.js b/tests/perf-test/SidebarLinks.perf-test.js
index 7c2d91b3356c..f6819d40a48f 100644
--- a/tests/perf-test/SidebarLinks.perf-test.js
+++ b/tests/perf-test/SidebarLinks.perf-test.js
@@ -1,13 +1,13 @@
-import {measurePerformance} from 'reassure';
-import Onyx from 'react-native-onyx';
import {fireEvent, screen} from '@testing-library/react-native';
+import Onyx from 'react-native-onyx';
+import {measurePerformance} from 'reassure';
import _ from 'underscore';
-import * as LHNTestUtils from '../utils/LHNTestUtils';
import CONST from '../../src/CONST';
import ONYXKEYS from '../../src/ONYXKEYS';
+import variables from '../../src/styles/variables';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
-import variables from '../../src/styles/variables';
/**
* Performance tests with Reassure can require big timeouts as all runs
diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js
index a9ffe258ac7f..54808d2b618d 100644
--- a/tests/ui/UnreadIndicatorsTest.js
+++ b/tests/ui/UnreadIndicatorsTest.js
@@ -1,29 +1,29 @@
-import React from 'react';
-import Onyx from 'react-native-onyx';
-import {Linking, AppState} from 'react-native';
import {fireEvent, render, screen, waitFor} from '@testing-library/react-native';
-import lodashGet from 'lodash/get';
-import {subMinutes, format, addSeconds, subSeconds} from 'date-fns';
+import {addSeconds, format, subMinutes, subSeconds} from 'date-fns';
import {utcToZonedTime} from 'date-fns-tz';
+import lodashGet from 'lodash/get';
+import React from 'react';
+import {AppState, Linking} from 'react-native';
+import Onyx from 'react-native-onyx';
import App from '../../src/App';
+import CONFIG from '../../src/CONFIG';
import CONST from '../../src/CONST';
-import ONYXKEYS from '../../src/ONYXKEYS';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct';
-import * as TestHelper from '../utils/TestHelper';
-import appSetup from '../../src/setup';
-import fontWeightBold from '../../src/styles/fontWeight/bold';
import * as AppActions from '../../src/libs/actions/App';
-import * as NumberUtils from '../../src/libs/NumberUtils';
-import LocalNotification from '../../src/libs/Notification/LocalNotification';
import * as Report from '../../src/libs/actions/Report';
+import * as User from '../../src/libs/actions/User';
import * as CollectionUtils from '../../src/libs/CollectionUtils';
import DateUtils from '../../src/libs/DateUtils';
-import * as User from '../../src/libs/actions/User';
+import * as Localize from '../../src/libs/Localize';
+import LocalNotification from '../../src/libs/Notification/LocalNotification';
+import * as NumberUtils from '../../src/libs/NumberUtils';
import * as Pusher from '../../src/libs/Pusher/pusher';
import PusherConnectionManager from '../../src/libs/PusherConnectionManager';
-import CONFIG from '../../src/CONFIG';
-import * as Localize from '../../src/libs/Localize';
+import ONYXKEYS from '../../src/ONYXKEYS';
+import appSetup from '../../src/setup';
+import fontWeightBold from '../../src/styles/fontWeight/bold';
+import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import waitForBatchedUpdatesWithAct from '../utils/waitForBatchedUpdatesWithAct';
// We need a large timeout here as we are lazy loading React Navigation screens and this test is running against the entire mounted App
jest.setTimeout(30000);
@@ -221,7 +221,7 @@ describe('Unread Indicators', () => {
// And that the text is bold
const displayNameHintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames');
const displayNameText = screen.queryByLabelText(displayNameHintText);
- expect(lodashGet(displayNameText, ['props', 'style', 0, 'fontWeight'])).toBe(fontWeightBold);
+ expect(lodashGet(displayNameText, ['props', 'style', 'fontWeight'])).toBe(fontWeightBold);
return navigateToSidebarOption(0);
})
@@ -233,7 +233,6 @@ describe('Unread Indicators', () => {
const reportCommentsHintText = Localize.translateLocal('accessibilityHints.chatMessage');
const reportComments = screen.queryAllByLabelText(reportCommentsHintText);
expect(reportComments).toHaveLength(9);
-
// Since the last read timestamp is the timestamp of action 3 we should have an unread indicator above the next "unread" action which will
// have actionID of 4
const newMessageLineIndicatorHintText = Localize.translateLocal('accessibilityHints.newMessageLineIndicator');
@@ -241,12 +240,10 @@ describe('Unread Indicators', () => {
expect(unreadIndicator).toHaveLength(1);
const reportActionID = lodashGet(unreadIndicator, [0, 'props', 'data-action-id']);
expect(reportActionID).toBe('4');
-
// Scroll up and verify that the "New messages" badge appears
scrollUpToRevealNewMessagesBadge();
return waitFor(() => expect(isNewMessagesBadgeVisible()).toBe(true));
}));
-
it('Clear the new line indicator and bold when we navigate away from a chat that is now read', () =>
signInAndGetAppWithUnreadChat()
// Navigate to the unread chat from the sidebar
@@ -255,14 +252,12 @@ describe('Unread Indicators', () => {
.then(() => navigateToSidebarOption(0))
.then(() => {
expect(areYouOnChatListScreen()).toBe(false);
-
// Then navigate back to the sidebar
return navigateToSidebar();
})
.then(() => {
// Verify the LHN is now open
expect(areYouOnChatListScreen()).toBe(true);
-
// Tap on the chat again
return navigateToSidebarOption(0);
})
@@ -271,7 +266,6 @@ describe('Unread Indicators', () => {
const newMessageLineIndicatorHintText = Localize.translateLocal('accessibilityHints.newMessageLineIndicator');
const unreadIndicator = screen.queryAllByLabelText(newMessageLineIndicatorHintText);
expect(unreadIndicator).toHaveLength(0);
-
// Tap on the chat again
return navigateToSidebarOption(0);
})
@@ -282,7 +276,6 @@ describe('Unread Indicators', () => {
expect(unreadIndicator).toHaveLength(0);
expect(areYouOnChatListScreen()).toBe(false);
}));
-
it('Shows a browser notification and bold text when a new message arrives for a chat that is read', () =>
signInAndGetAppWithUnreadChat()
.then(() => {
@@ -291,7 +284,6 @@ describe('Unread Indicators', () => {
const NEW_REPORT_ID = '2';
const NEW_REPORT_CREATED_DATE = subSeconds(new Date(), 5);
const NEW_REPORT_FIST_MESSAGE_CREATED_DATE = addSeconds(NEW_REPORT_CREATED_DATE, 1);
-
const createdReportActionID = NumberUtils.rand64();
const commentReportActionID = NumberUtils.rand64();
const channel = Pusher.getChannel(`${CONST.PUSHER.PRIVATE_USER_CHANNEL_PREFIX}${USER_A_ACCOUNT_ID}${CONFIG.PUSHER.SUFFIX}`);
@@ -354,17 +346,16 @@ describe('Unread Indicators', () => {
const optionRowsHintText = Localize.translateLocal('accessibilityHints.navigatesToChat');
const optionRows = screen.queryAllByAccessibilityHint(optionRowsHintText);
expect(optionRows).toHaveLength(2);
-
// Verify the text for both chats are bold indicating that nothing has not yet been read
const displayNameHintTexts = Localize.translateLocal('accessibilityHints.chatUserDisplayNames');
const displayNameTexts = screen.queryAllByLabelText(displayNameHintTexts);
expect(displayNameTexts).toHaveLength(2);
const firstReportOption = displayNameTexts[0];
- expect(lodashGet(firstReportOption, ['props', 'style', 0, 'fontWeight'])).toBe(fontWeightBold);
+ expect(lodashGet(firstReportOption, ['props', 'style', 'fontWeight'])).toBe(fontWeightBold);
expect(lodashGet(firstReportOption, ['props', 'children'])).toBe('C User');
const secondReportOption = displayNameTexts[1];
- expect(lodashGet(secondReportOption, ['props', 'style', 0, 'fontWeight'])).toBe(fontWeightBold);
+ expect(lodashGet(secondReportOption, ['props', 'style', 'fontWeight'])).toBe(fontWeightBold);
expect(lodashGet(secondReportOption, ['props', 'children'])).toBe('B User');
// Tap the new report option and navigate back to the sidebar again via the back button
@@ -376,9 +367,9 @@ describe('Unread Indicators', () => {
const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames');
const displayNameTexts = screen.queryAllByLabelText(hintText);
expect(displayNameTexts).toHaveLength(2);
- expect(lodashGet(displayNameTexts[0], ['props', 'style', 0, 'fontWeight'])).toBe(undefined);
+ expect(lodashGet(displayNameTexts[0], ['props', 'style', 'fontWeight'])).toBe(undefined);
expect(lodashGet(displayNameTexts[0], ['props', 'children'])).toBe('C User');
- expect(lodashGet(displayNameTexts[1], ['props', 'style', 0, 'fontWeight'])).toBe(fontWeightBold);
+ expect(lodashGet(displayNameTexts[1], ['props', 'style', 'fontWeight'])).toBe(fontWeightBold);
expect(lodashGet(displayNameTexts[1], ['props', 'children'])).toBe('B User');
}));
@@ -399,12 +390,10 @@ describe('Unread Indicators', () => {
expect(unreadIndicator).toHaveLength(1);
const reportActionID = lodashGet(unreadIndicator, [0, 'props', 'data-action-id']);
expect(reportActionID).toBe('3');
-
// Scroll up and verify the new messages badge appears
scrollUpToRevealNewMessagesBadge();
return waitFor(() => expect(isNewMessagesBadgeVisible()).toBe(true));
})
-
// Navigate to the sidebar
.then(navigateToSidebar)
.then(() => {
@@ -412,7 +401,7 @@ describe('Unread Indicators', () => {
const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames');
const displayNameTexts = screen.queryAllByLabelText(hintText);
expect(displayNameTexts).toHaveLength(1);
- expect(lodashGet(displayNameTexts[0], ['props', 'style', 0, 'fontWeight'])).toBe(fontWeightBold);
+ expect(lodashGet(displayNameTexts[0], ['props', 'style', 'fontWeight'])).toBe(fontWeightBold);
expect(lodashGet(displayNameTexts[0], ['props', 'children'])).toBe('B User');
// Navigate to the report again and back to the sidebar
@@ -424,7 +413,7 @@ describe('Unread Indicators', () => {
const hintText = Localize.translateLocal('accessibilityHints.chatUserDisplayNames');
const displayNameTexts = screen.queryAllByLabelText(hintText);
expect(displayNameTexts).toHaveLength(1);
- expect(lodashGet(displayNameTexts[0], ['props', 'style', 0, 'fontWeight'])).toBe(undefined);
+ expect(lodashGet(displayNameTexts[0], ['props', 'style', 'fontWeight'])).toBe(undefined);
expect(lodashGet(displayNameTexts[0], ['props', 'children'])).toBe('B User');
// Navigate to the report again and verify the new line indicator is missing
diff --git a/tests/unit/APITest.js b/tests/unit/APITest.js
index 395f1438b666..474ccbf36328 100644
--- a/tests/unit/APITest.js
+++ b/tests/unit/APITest.js
@@ -1,18 +1,17 @@
import Onyx from 'react-native-onyx';
import _ from 'underscore';
-
-import * as TestHelper from '../utils/TestHelper';
-import HttpUtils from '../../src/libs/HttpUtils';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import ONYXKEYS from '../../src/ONYXKEYS';
import CONST from '../../src/CONST';
-import * as NetworkStore from '../../src/libs/Network/NetworkStore';
import * as PersistedRequests from '../../src/libs/actions/PersistedRequests';
-import * as MainQueue from '../../src/libs/Network/MainQueue';
import * as API from '../../src/libs/API';
+import HttpUtils from '../../src/libs/HttpUtils';
+import * as MainQueue from '../../src/libs/Network/MainQueue';
+import * as NetworkStore from '../../src/libs/Network/NetworkStore';
import * as SequentialQueue from '../../src/libs/Network/SequentialQueue';
import * as Request from '../../src/libs/Request';
import * as RequestThrottle from '../../src/libs/RequestThrottle';
+import ONYXKEYS from '../../src/ONYXKEYS';
+import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import waitForNetworkPromises from '../utils/waitForNetworkPromises';
jest.mock('../../src/libs/Log');
diff --git a/tests/unit/CalendarPickerTest.js b/tests/unit/CalendarPickerTest.js
index 512a86a25e19..5d0c22459710 100644
--- a/tests/unit/CalendarPickerTest.js
+++ b/tests/unit/CalendarPickerTest.js
@@ -1,8 +1,8 @@
-import {render, fireEvent, within} from '@testing-library/react-native';
-import {format, eachMonthOfInterval, subYears, addYears} from 'date-fns';
-import DateUtils from '../../src/libs/DateUtils';
+import {fireEvent, render, within} from '@testing-library/react-native';
+import {addYears, eachMonthOfInterval, format, subYears} from 'date-fns';
import CalendarPicker from '../../src/components/NewDatePicker/CalendarPicker';
import CONST from '../../src/CONST';
+import DateUtils from '../../src/libs/DateUtils';
DateUtils.setLocale(CONST.LOCALES.EN);
const fullYear = new Date().getFullYear();
@@ -18,14 +18,20 @@ jest.mock('@react-navigation/native', () => ({
createNavigationContainerRef: jest.fn(),
}));
-jest.mock('../../src/components/withLocalize', () => (Component) => (props) => (
- ''}
- preferredLocale="en"
- />
-));
+jest.mock('../../src/components/withLocalize', () => (Component) => {
+ function WrappedComponent(props) {
+ return (
+ ''}
+ preferredLocale="en"
+ />
+ );
+ }
+ WrappedComponent.displayName = `WrappedComponent`;
+ return WrappedComponent;
+});
jest.mock('../../src/hooks/useLocalize', () =>
jest.fn(() => ({
diff --git a/tests/unit/CurrencyUtilsTest.js b/tests/unit/CurrencyUtilsTest.js
index ba61775f30da..89e1e2ffb3be 100644
--- a/tests/unit/CurrencyUtilsTest.js
+++ b/tests/unit/CurrencyUtilsTest.js
@@ -1,11 +1,10 @@
-import _ from 'underscore';
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../src/ONYXKEYS';
+import _ from 'underscore';
import CONST from '../../src/CONST';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import * as CurrencyUtils from '../../src/libs/CurrencyUtils';
import LocaleListener from '../../src/libs/Localize/LocaleListener';
-
+import ONYXKEYS from '../../src/ONYXKEYS';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
// This file can get outdated. In that case, you can follow these steps to update it:
// - open your browser console and navigate to the Network tab
// - refresh the App
diff --git a/tests/unit/DateUtilsTest.js b/tests/unit/DateUtilsTest.js
index 91590eb955b2..4b76e0f496c8 100644
--- a/tests/unit/DateUtilsTest.js
+++ b/tests/unit/DateUtilsTest.js
@@ -1,6 +1,6 @@
-import Onyx from 'react-native-onyx';
+import {addDays, addMinutes, format, setHours, setMinutes, subDays, subHours, subMinutes, subSeconds} from 'date-fns';
import {format as tzFormat, utcToZonedTime} from 'date-fns-tz';
-import {addMinutes, subHours, subMinutes, subSeconds, format, setMinutes, setHours, subDays, addDays} from 'date-fns';
+import Onyx from 'react-native-onyx';
import CONST from '../../src/CONST';
import DateUtils from '../../src/libs/DateUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
diff --git a/tests/unit/EmojiTest.js b/tests/unit/EmojiTest.js
index d10da618480e..4da29027de86 100644
--- a/tests/unit/EmojiTest.js
+++ b/tests/unit/EmojiTest.js
@@ -1,14 +1,14 @@
-import _ from 'underscore';
import {getUnixTime} from 'date-fns';
-import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
import Emoji from '../../assets/emojis';
+import CONST from '../../src/CONST';
+import * as User from '../../src/libs/actions/User';
import * as EmojiUtils from '../../src/libs/EmojiUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
-import * as User from '../../src/libs/actions/User';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import * as TestHelper from '../utils/TestHelper';
-import CONST from '../../src/CONST';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
describe('EmojiTest', () => {
it('matches all the emojis in the list', () => {
diff --git a/tests/unit/IOUUtilsTest.js b/tests/unit/IOUUtilsTest.js
index 9785acf68317..ac04b74a0ca5 100644
--- a/tests/unit/IOUUtilsTest.js
+++ b/tests/unit/IOUUtilsTest.js
@@ -1,10 +1,10 @@
import Onyx from 'react-native-onyx';
import * as IOUUtils from '../../src/libs/IOUUtils';
import * as ReportUtils from '../../src/libs/ReportUtils';
+import * as TransactionUtils from '../../src/libs/TransactionUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import currencyList from './currencyList.json';
-import * as TransactionUtils from '../../src/libs/TransactionUtils';
function initCurrencyList() {
Onyx.init({
diff --git a/tests/unit/LocalePhoneNumberTest.js b/tests/unit/LocalePhoneNumberTest.js
index 1435e0819fa4..99f53e7f980a 100644
--- a/tests/unit/LocalePhoneNumberTest.js
+++ b/tests/unit/LocalePhoneNumberTest.js
@@ -1,6 +1,6 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../src/ONYXKEYS';
import * as LocalePhoneNumber from '../../src/libs/LocalePhoneNumber';
+import ONYXKEYS from '../../src/ONYXKEYS';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
const ES_NUMBER = '+34702474537';
diff --git a/tests/unit/LocalizeTests.js b/tests/unit/LocalizeTests.js
index 921cf158a47c..4c89d587fc06 100644
--- a/tests/unit/LocalizeTests.js
+++ b/tests/unit/LocalizeTests.js
@@ -1,8 +1,8 @@
import Onyx from 'react-native-onyx';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import CONST from '../../src/CONST';
-import ONYXKEYS from '../../src/ONYXKEYS';
import * as Localize from '../../src/libs/Localize';
+import ONYXKEYS from '../../src/ONYXKEYS';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
describe('localize', () => {
beforeAll(() => {
diff --git a/tests/unit/LoginUtilsTest.js b/tests/unit/LoginUtilsTest.js
index e49d710b8f49..b27ffdbb3897 100644
--- a/tests/unit/LoginUtilsTest.js
+++ b/tests/unit/LoginUtilsTest.js
@@ -1,7 +1,7 @@
import Onyx from 'react-native-onyx';
+import * as LoginUtils from '../../src/libs/LoginUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import * as LoginUtils from '../../src/libs/LoginUtils';
describe('LoginUtils', () => {
beforeAll(() => {
diff --git a/tests/unit/MiddlewareTest.js b/tests/unit/MiddlewareTest.js
index db020ea924ed..85148cdb40e0 100644
--- a/tests/unit/MiddlewareTest.js
+++ b/tests/unit/MiddlewareTest.js
@@ -1,12 +1,12 @@
import Onyx from 'react-native-onyx';
+import HttpUtils from '../../src/libs/HttpUtils';
+import * as MainQueue from '../../src/libs/Network/MainQueue';
import * as NetworkStore from '../../src/libs/Network/NetworkStore';
-import * as Request from '../../src/libs/Request';
import * as SequentialQueue from '../../src/libs/Network/SequentialQueue';
+import * as Request from '../../src/libs/Request';
+import ONYXKEYS from '../../src/ONYXKEYS';
import * as TestHelper from '../utils/TestHelper';
import waitForNetworkPromises from '../utils/waitForNetworkPromises';
-import ONYXKEYS from '../../src/ONYXKEYS';
-import * as MainQueue from '../../src/libs/Network/MainQueue';
-import HttpUtils from '../../src/libs/HttpUtils';
Onyx.init({
keys: ONYXKEYS,
diff --git a/tests/unit/MigrationTest.js b/tests/unit/MigrationTest.js
index d0e7f19d3d3f..4bd739a08a59 100644
--- a/tests/unit/MigrationTest.js
+++ b/tests/unit/MigrationTest.js
@@ -1,10 +1,11 @@
import Onyx from 'react-native-onyx';
import _ from 'underscore';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import Log from '../../src/libs/Log';
-import PersonalDetailsByAccountID from '../../src/libs/migrations/PersonalDetailsByAccountID';
import CheckForPreviousReportActionID from '../../src/libs/migrations/CheckForPreviousReportActionID';
+import KeyReportActionsDraftByReportActionID from '../../src/libs/migrations/KeyReportActionsDraftByReportActionID';
+import PersonalDetailsByAccountID from '../../src/libs/migrations/PersonalDetailsByAccountID';
import ONYXKEYS from '../../src/ONYXKEYS';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
jest.mock('../../src/libs/getPlatform');
@@ -622,4 +623,83 @@ describe('Migrations', () => {
});
}));
});
+
+ describe('KeyReportActionsDraftByReportActionID', () => {
+ it("Should work even if there's no reportActionsDrafts data in Onyx", () =>
+ KeyReportActionsDraftByReportActionID().then(() =>
+ expect(LogSpy).toHaveBeenCalledWith('[Migrate Onyx] Skipped migration KeyReportActionsDraftByReportActionID because there were no reportActionsDrafts'),
+ ));
+
+ it('Should move individual draft to a draft collection of report', () =>
+ Onyx.multiSet({
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_1`]: 'a',
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_2`]: 'b',
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2`]: {3: 'c'},
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2_4`]: 'd',
+ })
+ .then(KeyReportActionsDraftByReportActionID)
+ .then(() => {
+ const connectionID = Onyx.connect({
+ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS,
+ waitForCollectionCallback: true,
+ callback: (allReportActionsDrafts) => {
+ Onyx.disconnect(connectionID);
+ const expectedReportActionDraft1 = {
+ 1: 'a',
+ 2: 'b',
+ };
+ const expectedReportActionDraft2 = {
+ 3: 'c',
+ 4: 'd',
+ };
+ expect(allReportActionsDrafts[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_1`]).toBeUndefined();
+ expect(allReportActionsDrafts[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_2`]).toBeUndefined();
+ expect(allReportActionsDrafts[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2_4`]).toBeUndefined();
+ expect(allReportActionsDrafts[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1`]).toMatchObject(expectedReportActionDraft1);
+ expect(allReportActionsDrafts[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2`]).toMatchObject(expectedReportActionDraft2);
+ },
+ });
+ }));
+
+ it('Should skip if nothing to migrate', () =>
+ Onyx.multiSet({
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_1`]: null,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_2`]: null,
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2`]: {},
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2_4`]: null,
+ })
+ .then(KeyReportActionsDraftByReportActionID)
+ .then(() => {
+ expect(LogSpy).toHaveBeenCalledWith('[Migrate Onyx] Skipped migration KeyReportActionsDraftByReportActionID because there are no actions drafts to migrate');
+ const connectionID = Onyx.connect({
+ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS,
+ waitForCollectionCallback: true,
+ callback: (allReportActions) => {
+ Onyx.disconnect(connectionID);
+ const expectedReportActionDraft = {};
+ expect(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_1`]).toBeUndefined();
+ expect(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_2`]).toBeUndefined();
+ expect(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2_4`]).toBeUndefined();
+ expect(allReportActions[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}2`]).toMatchObject(expectedReportActionDraft);
+ },
+ });
+ }));
+
+ it("Shouldn't move empty individual draft to a draft collection of report", () =>
+ Onyx.multiSet({
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_1`]: '',
+ [`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1`]: {},
+ })
+ .then(KeyReportActionsDraftByReportActionID)
+ .then(() => {
+ const connectionID = Onyx.connect({
+ key: ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS,
+ waitForCollectionCallback: true,
+ callback: (allReportActionsDrafts) => {
+ Onyx.disconnect(connectionID);
+ expect(allReportActionsDrafts[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS_DRAFTS}1_1`]).toBeUndefined();
+ },
+ });
+ }));
+ });
});
diff --git a/tests/unit/NetworkTest.js b/tests/unit/NetworkTest.js
index bd45ae3c2187..9a90a100769f 100644
--- a/tests/unit/NetworkTest.js
+++ b/tests/unit/NetworkTest.js
@@ -1,20 +1,19 @@
-import _ from 'underscore';
import Onyx from 'react-native-onyx';
-
-import * as TestHelper from '../utils/TestHelper';
-import HttpUtils from '../../src/libs/HttpUtils';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import ONYXKEYS from '../../src/ONYXKEYS';
+import _ from 'underscore';
import CONST from '../../src/CONST';
-import * as Network from '../../src/libs/Network';
-import * as NetworkStore from '../../src/libs/Network/NetworkStore';
-import * as Session from '../../src/libs/actions/Session';
+import * as App from '../../src/libs/actions/App';
+import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager';
import * as PersistedRequests from '../../src/libs/actions/PersistedRequests';
+import * as Session from '../../src/libs/actions/Session';
+import HttpUtils from '../../src/libs/HttpUtils';
import Log from '../../src/libs/Log';
+import * as Network from '../../src/libs/Network';
import * as MainQueue from '../../src/libs/Network/MainQueue';
-import * as App from '../../src/libs/actions/App';
+import * as NetworkStore from '../../src/libs/Network/NetworkStore';
import NetworkConnection from '../../src/libs/NetworkConnection';
-import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager';
+import ONYXKEYS from '../../src/ONYXKEYS';
+import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
jest.mock('../../src/libs/Log');
diff --git a/tests/unit/OptionsListUtilsTest.js b/tests/unit/OptionsListUtilsTest.js
index eda743f85aa2..5d18608a3de4 100644
--- a/tests/unit/OptionsListUtilsTest.js
+++ b/tests/unit/OptionsListUtilsTest.js
@@ -1,11 +1,11 @@
-import _ from 'underscore';
-import Onyx from 'react-native-onyx';
import {View} from 'react-native';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
+import CONST from '../../src/CONST';
import * as OptionsListUtils from '../../src/libs/OptionsListUtils';
import * as ReportUtils from '../../src/libs/ReportUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import CONST from '../../src/CONST';
describe('OptionsListUtils', () => {
// Given a set of reports with both single participants and multiple participants some pinned and some not
@@ -702,13 +702,6 @@ describe('OptionsListUtils', () => {
shouldShow: false,
indexOffset: 0,
data: [
- {
- text: 'Restaurant',
- keyForList: 'Restaurant',
- searchText: 'Restaurant',
- tooltipText: 'Restaurant',
- isDisabled: false,
- },
{
text: 'Food',
keyForList: 'Food',
@@ -718,11 +711,18 @@ describe('OptionsListUtils', () => {
},
{
text: ' Meat',
- keyForList: 'Meat',
+ keyForList: 'Food: Meat',
searchText: 'Food: Meat',
tooltipText: 'Meat',
isDisabled: false,
},
+ {
+ text: 'Restaurant',
+ keyForList: 'Restaurant',
+ searchText: 'Restaurant',
+ tooltipText: 'Restaurant',
+ isDisabled: false,
+ },
],
},
];
@@ -847,13 +847,27 @@ describe('OptionsListUtils', () => {
{
title: 'All',
shouldShow: true,
- indexOffset: 3,
+ indexOffset: 2,
data: [
{
- text: 'Restaurant',
- keyForList: 'Restaurant',
- searchText: 'Restaurant',
- tooltipText: 'Restaurant',
+ text: 'Cars',
+ keyForList: 'Cars',
+ searchText: 'Cars',
+ tooltipText: 'Cars',
+ isDisabled: true,
+ },
+ {
+ text: ' Audi',
+ keyForList: 'Cars: Audi',
+ searchText: 'Cars: Audi',
+ tooltipText: 'Audi',
+ isDisabled: false,
+ },
+ {
+ text: ' Mercedes-Benz',
+ keyForList: 'Cars: Mercedes-Benz',
+ searchText: 'Cars: Mercedes-Benz',
+ tooltipText: 'Mercedes-Benz',
isDisabled: false,
},
{
@@ -865,37 +879,23 @@ describe('OptionsListUtils', () => {
},
{
text: ' Meat',
- keyForList: 'Meat',
+ keyForList: 'Food: Meat',
searchText: 'Food: Meat',
tooltipText: 'Meat',
isDisabled: false,
},
{
text: ' Milk',
- keyForList: 'Milk',
+ keyForList: 'Food: Milk',
searchText: 'Food: Milk',
tooltipText: 'Milk',
isDisabled: false,
},
{
- text: 'Cars',
- keyForList: 'Cars',
- searchText: 'Cars',
- tooltipText: 'Cars',
- isDisabled: true,
- },
- {
- text: ' Audi',
- keyForList: 'Audi',
- searchText: 'Cars: Audi',
- tooltipText: 'Audi',
- isDisabled: false,
- },
- {
- text: ' Mercedes-Benz',
- keyForList: 'Mercedes-Benz',
- searchText: 'Cars: Mercedes-Benz',
- tooltipText: 'Mercedes-Benz',
+ text: 'Restaurant',
+ keyForList: 'Restaurant',
+ searchText: 'Restaurant',
+ tooltipText: 'Restaurant',
isDisabled: false,
},
{
@@ -907,21 +907,21 @@ describe('OptionsListUtils', () => {
},
{
text: ' Meals',
- keyForList: 'Meals',
+ keyForList: 'Travel: Meals',
searchText: 'Travel: Meals',
tooltipText: 'Meals',
isDisabled: false,
},
{
text: ' Breakfast',
- keyForList: 'Breakfast',
+ keyForList: 'Travel: Meals: Breakfast',
searchText: 'Travel: Meals: Breakfast',
tooltipText: 'Breakfast',
isDisabled: false,
},
{
text: ' Lunch',
- keyForList: 'Lunch',
+ keyForList: 'Travel: Meals: Lunch',
searchText: 'Travel: Meals: Lunch',
tooltipText: 'Lunch',
isDisabled: false,
@@ -1356,9 +1356,9 @@ describe('OptionsListUtils', () => {
it('getCategoryOptionTree()', () => {
const categories = {
- Taxi: {
- enabled: false,
- name: 'Taxi',
+ Meals: {
+ enabled: true,
+ name: 'Meals',
},
Restaurant: {
enabled: true,
@@ -1376,26 +1376,14 @@ describe('OptionsListUtils', () => {
enabled: true,
name: 'Food: Milk',
},
- 'Food: Vegetables': {
- enabled: false,
- name: 'Food: Vegetables',
- },
'Cars: Audi': {
enabled: true,
name: 'Cars: Audi',
},
- 'Cars: BMW': {
- enabled: false,
- name: 'Cars: BMW',
- },
'Cars: Mercedes-Benz': {
enabled: true,
name: 'Cars: Mercedes-Benz',
},
- Medical: {
- enabled: false,
- name: 'Medical',
- },
'Travel: Meals': {
enabled: true,
name: 'Travel: Meals',
@@ -1404,10 +1392,6 @@ describe('OptionsListUtils', () => {
enabled: true,
name: 'Travel: Meals: Breakfast',
},
- 'Travel: Meals: Dinner': {
- enabled: false,
- name: 'Travel: Meals: Dinner',
- },
'Travel: Meals: Lunch': {
enabled: true,
name: 'Travel: Meals: Lunch',
@@ -1416,6 +1400,10 @@ describe('OptionsListUtils', () => {
enabled: true,
name: 'Plain',
},
+ Audi: {
+ enabled: true,
+ name: 'Audi',
+ },
Health: {
enabled: true,
name: 'Health',
@@ -1430,6 +1418,13 @@ describe('OptionsListUtils', () => {
},
};
const result = [
+ {
+ text: 'Meals',
+ keyForList: 'Meals',
+ searchText: 'Meals',
+ tooltipText: 'Meals',
+ isDisabled: false,
+ },
{
text: 'Restaurant',
keyForList: 'Restaurant',
@@ -1446,14 +1441,14 @@ describe('OptionsListUtils', () => {
},
{
text: ' Meat',
- keyForList: 'Meat',
+ keyForList: 'Food: Meat',
searchText: 'Food: Meat',
tooltipText: 'Meat',
isDisabled: false,
},
{
text: ' Milk',
- keyForList: 'Milk',
+ keyForList: 'Food: Milk',
searchText: 'Food: Milk',
tooltipText: 'Milk',
isDisabled: false,
@@ -1467,14 +1462,14 @@ describe('OptionsListUtils', () => {
},
{
text: ' Audi',
- keyForList: 'Audi',
+ keyForList: 'Cars: Audi',
searchText: 'Cars: Audi',
tooltipText: 'Audi',
isDisabled: false,
},
{
text: ' Mercedes-Benz',
- keyForList: 'Mercedes-Benz',
+ keyForList: 'Cars: Mercedes-Benz',
searchText: 'Cars: Mercedes-Benz',
tooltipText: 'Mercedes-Benz',
isDisabled: false,
@@ -1488,21 +1483,21 @@ describe('OptionsListUtils', () => {
},
{
text: ' Meals',
- keyForList: 'Meals',
+ keyForList: 'Travel: Meals',
searchText: 'Travel: Meals',
tooltipText: 'Meals',
isDisabled: false,
},
{
text: ' Breakfast',
- keyForList: 'Breakfast',
+ keyForList: 'Travel: Meals: Breakfast',
searchText: 'Travel: Meals: Breakfast',
tooltipText: 'Breakfast',
isDisabled: false,
},
{
text: ' Lunch',
- keyForList: 'Lunch',
+ keyForList: 'Travel: Meals: Lunch',
searchText: 'Travel: Meals: Lunch',
tooltipText: 'Lunch',
isDisabled: false,
@@ -1514,6 +1509,13 @@ describe('OptionsListUtils', () => {
tooltipText: 'Plain',
isDisabled: false,
},
+ {
+ text: 'Audi',
+ keyForList: 'Audi',
+ searchText: 'Audi',
+ tooltipText: 'Audi',
+ isDisabled: false,
+ },
{
text: 'Health',
keyForList: 'Health',
@@ -1530,35 +1532,458 @@ describe('OptionsListUtils', () => {
},
{
text: ' B',
- keyForList: 'B',
+ keyForList: 'A: B',
searchText: 'A: B',
tooltipText: 'B',
isDisabled: true,
},
{
text: ' C',
- keyForList: 'C',
+ keyForList: 'A: B: C',
searchText: 'A: B: C',
tooltipText: 'C',
isDisabled: false,
},
{
text: ' D',
- keyForList: 'D',
+ keyForList: 'A: B: C: D',
searchText: 'A: B: C: D',
tooltipText: 'D',
isDisabled: true,
},
{
text: ' E',
- keyForList: 'E',
+ keyForList: 'A: B: C: D: E',
searchText: 'A: B: C: D: E',
tooltipText: 'E',
isDisabled: false,
},
];
+ const resultOneLine = [
+ {
+ text: 'Meals',
+ keyForList: 'Meals',
+ searchText: 'Meals',
+ tooltipText: 'Meals',
+ isDisabled: false,
+ },
+ {
+ text: 'Restaurant',
+ keyForList: 'Restaurant',
+ searchText: 'Restaurant',
+ tooltipText: 'Restaurant',
+ isDisabled: false,
+ },
+ {
+ text: 'Food',
+ keyForList: 'Food',
+ searchText: 'Food',
+ tooltipText: 'Food',
+ isDisabled: false,
+ },
+ {
+ text: 'Food: Meat',
+ keyForList: 'Food: Meat',
+ searchText: 'Food: Meat',
+ tooltipText: 'Food: Meat',
+ isDisabled: false,
+ },
+ {
+ text: 'Food: Milk',
+ keyForList: 'Food: Milk',
+ searchText: 'Food: Milk',
+ tooltipText: 'Food: Milk',
+ isDisabled: false,
+ },
+ {
+ text: 'Cars: Audi',
+ keyForList: 'Cars: Audi',
+ searchText: 'Cars: Audi',
+ tooltipText: 'Cars: Audi',
+ isDisabled: false,
+ },
+ {
+ text: 'Cars: Mercedes-Benz',
+ keyForList: 'Cars: Mercedes-Benz',
+ searchText: 'Cars: Mercedes-Benz',
+ tooltipText: 'Cars: Mercedes-Benz',
+ isDisabled: false,
+ },
+ {
+ text: 'Travel: Meals',
+ keyForList: 'Travel: Meals',
+ searchText: 'Travel: Meals',
+ tooltipText: 'Travel: Meals',
+ isDisabled: false,
+ },
+ {
+ text: 'Travel: Meals: Breakfast',
+ keyForList: 'Travel: Meals: Breakfast',
+ searchText: 'Travel: Meals: Breakfast',
+ tooltipText: 'Travel: Meals: Breakfast',
+ isDisabled: false,
+ },
+ {
+ text: 'Travel: Meals: Lunch',
+ keyForList: 'Travel: Meals: Lunch',
+ searchText: 'Travel: Meals: Lunch',
+ tooltipText: 'Travel: Meals: Lunch',
+ isDisabled: false,
+ },
+ {
+ text: 'Plain',
+ keyForList: 'Plain',
+ searchText: 'Plain',
+ tooltipText: 'Plain',
+ isDisabled: false,
+ },
+ {
+ text: 'Audi',
+ keyForList: 'Audi',
+ searchText: 'Audi',
+ tooltipText: 'Audi',
+ isDisabled: false,
+ },
+ {
+ text: 'Health',
+ keyForList: 'Health',
+ searchText: 'Health',
+ tooltipText: 'Health',
+ isDisabled: false,
+ },
+ {
+ text: 'A: B: C',
+ keyForList: 'A: B: C',
+ searchText: 'A: B: C',
+ tooltipText: 'A: B: C',
+ isDisabled: false,
+ },
+ {
+ text: 'A: B: C: D: E',
+ keyForList: 'A: B: C: D: E',
+ searchText: 'A: B: C: D: E',
+ tooltipText: 'A: B: C: D: E',
+ isDisabled: false,
+ },
+ ];
expect(OptionsListUtils.getCategoryOptionTree(categories)).toStrictEqual(result);
+ expect(OptionsListUtils.getCategoryOptionTree(categories, true)).toStrictEqual(resultOneLine);
+ });
+
+ it('sortCategories', () => {
+ const categoriesIncorrectOrdering = {
+ Taxi: {
+ name: 'Taxi',
+ enabled: false,
+ },
+ 'Test1: Subtest2': {
+ name: 'Test1: Subtest2',
+ enabled: true,
+ },
+ 'Test: Test1: Subtest4': {
+ name: 'Test: Test1: Subtest4',
+ enabled: true,
+ },
+ Taxes: {
+ name: 'Taxes',
+ enabled: true,
+ },
+ Test: {
+ name: 'Test',
+ enabled: true,
+ },
+ Test1: {
+ name: 'Test1',
+ enabled: true,
+ },
+ 'Travel: Nested-Travel': {
+ name: 'Travel: Nested-Travel',
+ enabled: true,
+ },
+ 'Test1: Subtest1': {
+ name: 'Test1: Subtest1',
+ enabled: true,
+ },
+ 'Test: Test1': {
+ name: 'Test: Test1',
+ enabled: true,
+ },
+ 'Test: Test1: Subtest1': {
+ name: 'Test: Test1: Subtest1',
+ enabled: true,
+ },
+ 'Test: Test1: Subtest3': {
+ name: 'Test: Test1: Subtest3',
+ enabled: false,
+ },
+ 'Test: Test1: Subtest2': {
+ name: 'Test: Test1: Subtest2',
+ enabled: true,
+ },
+ 'Test: Test2': {
+ name: 'Test: Test2',
+ enabled: true,
+ },
+ Travel: {
+ name: 'Travel',
+ enabled: true,
+ },
+ Utilities: {
+ name: 'Utilities',
+ enabled: true,
+ },
+ 'Test: Test3: Subtest1': {
+ name: 'Test: Test3: Subtest1',
+ enabled: true,
+ },
+ 'Test1: Subtest3': {
+ name: 'Test1: Subtest3',
+ enabled: true,
+ },
+ };
+ const result = [
+ {
+ name: 'Taxes',
+ enabled: true,
+ },
+ {
+ name: 'Taxi',
+ enabled: false,
+ },
+ {
+ name: 'Test',
+ enabled: true,
+ },
+ {
+ name: 'Test: Test1',
+ enabled: true,
+ },
+ {
+ name: 'Test: Test1: Subtest1',
+ enabled: true,
+ },
+ {
+ name: 'Test: Test1: Subtest2',
+ enabled: true,
+ },
+ {
+ name: 'Test: Test1: Subtest3',
+ enabled: false,
+ },
+ {
+ name: 'Test: Test1: Subtest4',
+ enabled: true,
+ },
+ {
+ name: 'Test: Test2',
+ enabled: true,
+ },
+ {
+ name: 'Test: Test3: Subtest1',
+ enabled: true,
+ },
+ {
+ name: 'Test1',
+ enabled: true,
+ },
+ {
+ name: 'Test1: Subtest1',
+ enabled: true,
+ },
+ {
+ name: 'Test1: Subtest2',
+ enabled: true,
+ },
+ {
+ name: 'Test1: Subtest3',
+ enabled: true,
+ },
+ {
+ name: 'Travel',
+ enabled: true,
+ },
+ {
+ name: 'Travel: Nested-Travel',
+ enabled: true,
+ },
+ {
+ name: 'Utilities',
+ enabled: true,
+ },
+ ];
+ const categoriesIncorrectOrdering2 = {
+ 'Cars: BMW': {
+ enabled: false,
+ name: 'Cars: BMW',
+ },
+ Medical: {
+ enabled: false,
+ name: 'Medical',
+ },
+ 'Travel: Meals: Lunch': {
+ enabled: true,
+ name: 'Travel: Meals: Lunch',
+ },
+ 'Cars: Mercedes-Benz': {
+ enabled: true,
+ name: 'Cars: Mercedes-Benz',
+ },
+ Food: {
+ enabled: true,
+ name: 'Food',
+ },
+ 'Food: Meat': {
+ enabled: true,
+ name: 'Food: Meat',
+ },
+ 'Travel: Meals: Dinner': {
+ enabled: false,
+ name: 'Travel: Meals: Dinner',
+ },
+ 'Food: Vegetables': {
+ enabled: false,
+ name: 'Food: Vegetables',
+ },
+ Restaurant: {
+ enabled: true,
+ name: 'Restaurant',
+ },
+ Taxi: {
+ enabled: false,
+ name: 'Taxi',
+ },
+ 'Food: Milk': {
+ enabled: true,
+ name: 'Food: Milk',
+ },
+ 'Travel: Meals': {
+ enabled: true,
+ name: 'Travel: Meals',
+ },
+ 'Travel: Meals: Breakfast': {
+ enabled: true,
+ name: 'Travel: Meals: Breakfast',
+ },
+ 'Cars: Audi': {
+ enabled: true,
+ name: 'Cars: Audi',
+ },
+ };
+ const result2 = [
+ {
+ enabled: true,
+ name: 'Cars: Audi',
+ },
+ {
+ enabled: false,
+ name: 'Cars: BMW',
+ },
+ {
+ enabled: true,
+ name: 'Cars: Mercedes-Benz',
+ },
+ {
+ enabled: true,
+ name: 'Food',
+ },
+ {
+ enabled: true,
+ name: 'Food: Meat',
+ },
+ {
+ enabled: true,
+ name: 'Food: Milk',
+ },
+ {
+ enabled: false,
+ name: 'Food: Vegetables',
+ },
+ {
+ enabled: false,
+ name: 'Medical',
+ },
+ {
+ enabled: true,
+ name: 'Restaurant',
+ },
+ {
+ enabled: false,
+ name: 'Taxi',
+ },
+ {
+ enabled: true,
+ name: 'Travel: Meals',
+ },
+ {
+ enabled: true,
+ name: 'Travel: Meals: Breakfast',
+ },
+ {
+ enabled: false,
+ name: 'Travel: Meals: Dinner',
+ },
+ {
+ enabled: true,
+ name: 'Travel: Meals: Lunch',
+ },
+ ];
+ const categoriesIncorrectOrdering3 = {
+ 'Movies: Mr. Nobody': {
+ enabled: true,
+ name: 'Movies: Mr. Nobody',
+ },
+ Movies: {
+ enabled: true,
+ name: 'Movies',
+ },
+ 'House, M.D.': {
+ enabled: true,
+ name: 'House, M.D.',
+ },
+ 'Dr. House': {
+ enabled: true,
+ name: 'Dr. House',
+ },
+ 'Many.dots.on.the.way.': {
+ enabled: true,
+ name: 'Many.dots.on.the.way.',
+ },
+ 'More.Many.dots.on.the.way.': {
+ enabled: false,
+ name: 'More.Many.dots.on.the.way.',
+ },
+ };
+ const result3 = [
+ {
+ enabled: true,
+ name: 'Dr. House',
+ },
+ {
+ enabled: true,
+ name: 'House, M.D.',
+ },
+ {
+ enabled: true,
+ name: 'Many.dots.on.the.way.',
+ },
+ {
+ enabled: false,
+ name: 'More.Many.dots.on.the.way.',
+ },
+ {
+ enabled: true,
+ name: 'Movies',
+ },
+ {
+ enabled: true,
+ name: 'Movies: Mr. Nobody',
+ },
+ ];
+
+ expect(OptionsListUtils.sortCategories(categoriesIncorrectOrdering)).toStrictEqual(result);
+ expect(OptionsListUtils.sortCategories(categoriesIncorrectOrdering2)).toStrictEqual(result2);
+ expect(OptionsListUtils.sortCategories(categoriesIncorrectOrdering3)).toStrictEqual(result3);
});
it('formatMemberForList()', () => {
diff --git a/tests/unit/ReportActionItemSingleTest.js b/tests/unit/ReportActionItemSingleTest.js
new file mode 100644
index 000000000000..55cae01c19f1
--- /dev/null
+++ b/tests/unit/ReportActionItemSingleTest.js
@@ -0,0 +1,86 @@
+import {cleanup, screen} from '@testing-library/react-native';
+import Onyx from 'react-native-onyx';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
+
+const ONYXKEYS = {
+ PERSONAL_DETAILS_LIST: 'personalDetailsList',
+ IS_LOADING_REPORT_DATA: 'isLoadingReportData',
+ COLLECTION: {
+ REPORT_ACTIONS: 'reportActions_',
+ POLICY: 'policy_',
+ },
+ NETWORK: 'network',
+};
+
+describe('ReportActionItemSingle', () => {
+ beforeAll(() =>
+ Onyx.init({
+ keys: ONYXKEYS,
+ registerStorageEventListener: () => {},
+ safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
+ }),
+ );
+
+ beforeEach(() => {
+ // Wrap Onyx each onyx action with waitForBatchedUpdates
+ wrapOnyxWithWaitForBatchedUpdates(Onyx);
+ // Initialize the network key for OfflineWithFeedback
+ return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false});
+ });
+
+ // Clear out Onyx after each test so that each test starts with a clean slate
+ afterEach(() => {
+ cleanup();
+ Onyx.clear();
+ });
+
+ describe('when the Report is a policy expense chat', () => {
+ describe('and the property "shouldShowSubscriptAvatar" is true', () => {
+ const shouldShowSubscriptAvatar = true;
+ const fakeReport = LHNTestUtils.getFakeReportWithPolicy([1, 2]);
+ const fakeReportAction = LHNTestUtils.getFakeAdvancedReportAction();
+ const fakePolicy = LHNTestUtils.getFakePolicy(fakeReport.policyID);
+ const fakePersonalDetails = {
+ [fakeReportAction.actorAccountID]: {
+ accountID: fakeReportAction.actorAccountID,
+ login: 'email1@test.com',
+ displayName: 'Email One',
+ avatar: 'https://example.com/avatar.png',
+ firstName: 'One',
+ },
+ };
+
+ beforeEach(() => {
+ LHNTestUtils.getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar, fakeReport, fakeReportAction);
+ });
+
+ function setup() {
+ return waitForBatchedUpdates().then(() =>
+ Onyx.multiSet({
+ [ONYXKEYS.PERSONAL_DETAILS_LIST]: fakePersonalDetails,
+ [ONYXKEYS.IS_LOADING_REPORT_DATA]: false,
+ [`${ONYXKEYS.COLLECTION.POLICY}${fakeReport.policyID}`]: fakePolicy,
+ }),
+ );
+ }
+
+ it('renders secondary Avatar properly', () => {
+ const expectedSecondaryIconTestId = 'SvgDefaultAvatar_w Icon';
+
+ return setup().then(() => {
+ expect(screen.getByTestId(expectedSecondaryIconTestId)).toBeDefined();
+ });
+ });
+
+ it('renders Person information', () => {
+ const [expectedPerson] = fakeReportAction.person;
+
+ return setup().then(() => {
+ expect(screen.getByText(expectedPerson.text)).toBeDefined();
+ });
+ });
+ });
+ });
+});
diff --git a/tests/unit/ReportActionsUtilsTest.js b/tests/unit/ReportActionsUtilsTest.js
index 2f02203bad64..9973515c44de 100644
--- a/tests/unit/ReportActionsUtilsTest.js
+++ b/tests/unit/ReportActionsUtilsTest.js
@@ -1,10 +1,10 @@
import Onyx from 'react-native-onyx';
import CONST from '../../src/CONST';
+import * as ReportActionsUtils from '../../src/libs/ReportActionsUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
-import * as ReportActionsUtils from '../../src/libs/ReportActionsUtils';
-import * as LHNTestUtils from '../utils/LHNTestUtils';
describe('ReportActionsUtils', () => {
beforeAll(() =>
diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js
index 26257b469939..2b836f8eb0bf 100644
--- a/tests/unit/ReportUtilsTest.js
+++ b/tests/unit/ReportUtilsTest.js
@@ -1,10 +1,10 @@
import Onyx from 'react-native-onyx';
import _ from 'underscore';
import CONST from '../../src/CONST';
-import ONYXKEYS from '../../src/ONYXKEYS';
import * as ReportUtils from '../../src/libs/ReportUtils';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import ONYXKEYS from '../../src/ONYXKEYS';
import * as LHNTestUtils from '../utils/LHNTestUtils';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
// Be sure to include the mocked permissions library or else the beta tests won't work
jest.mock('../../src/libs/Permissions');
diff --git a/tests/unit/RequestTest.js b/tests/unit/RequestTest.js
index fb1032e70cfe..823b05fd4e0e 100644
--- a/tests/unit/RequestTest.js
+++ b/tests/unit/RequestTest.js
@@ -1,6 +1,6 @@
import * as Request from '../../src/libs/Request';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
import * as TestHelper from '../utils/TestHelper';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
beforeAll(() => {
global.fetch = TestHelper.getGlobalFetchMock();
diff --git a/tests/unit/SidebarFilterTest.js b/tests/unit/SidebarFilterTest.js
index 18e499d89293..23a958e3aa9d 100644
--- a/tests/unit/SidebarFilterTest.js
+++ b/tests/unit/SidebarFilterTest.js
@@ -1,12 +1,12 @@
import {cleanup, screen} from '@testing-library/react-native';
-import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
-import * as LHNTestUtils from '../utils/LHNTestUtils';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
+import Onyx from 'react-native-onyx';
import CONST from '../../src/CONST';
import DateUtils from '../../src/libs/DateUtils';
import * as Localize from '../../src/libs/Localize';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
// Be sure to include the mocked permissions library or else the beta tests won't work
jest.mock('../../src/libs/Permissions');
diff --git a/tests/unit/SidebarOrderTest.js b/tests/unit/SidebarOrderTest.js
index 4a693d679b86..72b3a0c2f631 100644
--- a/tests/unit/SidebarOrderTest.js
+++ b/tests/unit/SidebarOrderTest.js
@@ -1,13 +1,13 @@
-import Onyx from 'react-native-onyx';
import {cleanup, screen} from '@testing-library/react-native';
import lodashGet from 'lodash/get';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
-import * as LHNTestUtils from '../utils/LHNTestUtils';
+import Onyx from 'react-native-onyx';
import CONST from '../../src/CONST';
+import * as Report from '../../src/libs/actions/Report';
import DateUtils from '../../src/libs/DateUtils';
import * as Localize from '../../src/libs/Localize';
-import * as Report from '../../src/libs/actions/Report';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
// Be sure to include the mocked Permissions and Expensicons libraries or else the beta tests won't work
jest.mock('../../src/libs/Permissions');
diff --git a/tests/unit/SidebarTest.js b/tests/unit/SidebarTest.js
index 1b5daa323da5..4bd0795aa3b9 100644
--- a/tests/unit/SidebarTest.js
+++ b/tests/unit/SidebarTest.js
@@ -1,11 +1,11 @@
-import Onyx from 'react-native-onyx';
import {cleanup, screen} from '@testing-library/react-native';
import lodashGet from 'lodash/get';
-import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
-import * as LHNTestUtils from '../utils/LHNTestUtils';
+import Onyx from 'react-native-onyx';
import CONST from '../../src/CONST';
import * as Localize from '../../src/libs/Localize';
+import * as LHNTestUtils from '../utils/LHNTestUtils';
+import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
// Be sure to include the mocked Permissions and Expensicons libraries or else the beta tests won't work
jest.mock('../../src/libs/Permissions');
diff --git a/tests/unit/ValidationUtilsTest.js b/tests/unit/ValidationUtilsTest.js
index a9e0b1b61128..bdc1f11948ae 100644
--- a/tests/unit/ValidationUtilsTest.js
+++ b/tests/unit/ValidationUtilsTest.js
@@ -1,4 +1,4 @@
-import {addDays, format, subYears, startOfDay} from 'date-fns';
+import {addDays, format, startOfDay, subYears} from 'date-fns';
import CONST from '../../src/CONST';
const ValidationUtils = require('../../src/libs/ValidationUtils');
diff --git a/tests/unit/enhanceParametersTest.js b/tests/unit/enhanceParametersTest.js
index fb2ccc86ad79..513206b42614 100644
--- a/tests/unit/enhanceParametersTest.js
+++ b/tests/unit/enhanceParametersTest.js
@@ -1,8 +1,8 @@
import Onyx from 'react-native-onyx';
-import ONYXKEYS from '../../src/ONYXKEYS';
+import CONFIG from '../../src/CONFIG';
import enhanceParameters from '../../src/libs/Network/enhanceParameters';
+import ONYXKEYS from '../../src/ONYXKEYS';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
-import CONFIG from '../../src/CONFIG';
beforeEach(() => Onyx.clear());
diff --git a/tests/unit/loginTest.js b/tests/unit/loginTest.js
index c8bcc6c6f00f..a1b59cfcb998 100644
--- a/tests/unit/loginTest.js
+++ b/tests/unit/loginTest.js
@@ -1,10 +1,8 @@
/**
* @format
*/
-
-import 'react-native';
import React from 'react';
-
+import 'react-native';
// Note: `react-test-renderer` renderer must be required after react-native.
import renderer from 'react-test-renderer';
import App from '../../src/App';
diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js
index ce4edc75b444..9898063cc496 100644
--- a/tests/utils/LHNTestUtils.js
+++ b/tests/utils/LHNTestUtils.js
@@ -1,14 +1,17 @@
-import React from 'react';
-import PropTypes from 'prop-types';
import {render} from '@testing-library/react-native';
+import PropTypes from 'prop-types';
+import React from 'react';
import ComposeProviders from '../../src/components/ComposeProviders';
-import OnyxProvider from '../../src/components/OnyxProvider';
import {LocaleContextProvider} from '../../src/components/LocaleContextProvider';
-import SidebarLinksData from '../../src/pages/home/sidebar/SidebarLinksData';
-import {EnvironmentProvider} from '../../src/components/withEnvironment';
+import OnyxProvider from '../../src/components/OnyxProvider';
import {CurrentReportIDContextProvider} from '../../src/components/withCurrentReportID';
+import {EnvironmentProvider} from '../../src/components/withEnvironment';
import CONST from '../../src/CONST';
import DateUtils from '../../src/libs/DateUtils';
+import ReportActionItemSingle from '../../src/pages/home/report/ReportActionItemSingle';
+import reportActionPropTypes from '../../src/pages/home/report/reportActionPropTypes';
+import SidebarLinksData from '../../src/pages/home/sidebar/SidebarLinksData';
+import reportPropTypes from '../../src/pages/reportPropTypes';
// we have to mock `useIsFocused` because it's used in the SidebarLinks component
const mockedNavigate = jest.fn();
@@ -167,6 +170,63 @@ function getAdvancedFakeReport(isArchived, isUserCreatedPolicyRoom, hasAddWorksp
};
}
+/**
+ * @param {Number[]} [participantAccountIDs]
+ * @param {Number} [millisecondsInThePast] the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages)
+ * @param {boolean} [isUnread]
+ * @returns {Object}
+ */
+function getFakeReportWithPolicy(participantAccountIDs = [1, 2], millisecondsInThePast = 0, isUnread = false) {
+ return {
+ ...getFakeReport(participantAccountIDs, millisecondsInThePast, isUnread),
+ type: CONST.REPORT.TYPE.CHAT,
+ chatType: CONST.REPORT.CHAT_TYPE.POLICY_EXPENSE_CHAT,
+ policyID: '08CE60F05A5D86E1',
+ oldPolicyName: '',
+ isOwnPolicyExpenseChat: false,
+ ownerAccountID: participantAccountIDs[0],
+ };
+}
+
+/**
+ * @param {Number} [id]
+ * @param {String} [name]
+ * @returns {Object}
+ */
+function getFakePolicy(id = 1, name = 'Workspace-Test-001') {
+ return {
+ id,
+ name,
+ isFromFullPolicy: false,
+ role: 'admin',
+ type: 'free',
+ owner: 'myuser@gmail.com',
+ outputCurrency: 'BRL',
+ avatar: '',
+ employeeList: [],
+ isPolicyExpenseChatEnabled: true,
+ areChatRoomsEnabled: true,
+ lastModified: 1697323926777105,
+ autoReporting: true,
+ autoReportingFrequency: 'immediate',
+ defaultBillable: false,
+ disabledFields: {defaultBillable: true, reimbursable: false},
+ };
+}
+
+/**
+ * @param {String} actionName
+ * @param {String} actor
+ * @param {Number} millisecondsInThePast the number of milliseconds in the past for the last message timestamp (to order reports by most recent messages)
+ * @returns {Object}
+ */
+function getFakeAdvancedReportAction(actionName = 'IOU', actor = 'email1@test.com', millisecondsInThePast = 0) {
+ return {
+ ...getFakeReportAction(actor, millisecondsInThePast),
+ actionName,
+ };
+}
+
/**
* @param {String} [currentReportID]
*/
@@ -218,4 +278,97 @@ MockedSidebarLinks.defaultProps = {
currentReportID: '',
};
-export {fakePersonalDetails, getDefaultRenderedSidebarLinks, getAdvancedFakeReport, getFakeReport, getFakeReportAction, MockedSidebarLinks};
+/**
+ * @param {React.ReactElement} component
+ */
+function internalRender(component) {
+ // A try-catch block needs to be added to the rendering so that any errors that happen while the component
+ // renders are caught and logged to the console. Without the try-catch block, Jest might only report the error
+ // as "The above error occurred in your component", without providing specific details. By using a try-catch block,
+ // any errors are caught and logged, allowing you to identify the exact error that might be causing a rendering issue
+ // when developing tests.
+
+ try {
+ render(component);
+ } catch (error) {
+ console.error(error);
+ }
+}
+
+/**
+ * @param {Boolean} [shouldShowSubscriptAvatar]
+ * @param {Object} [report]
+ * @param {Object} [reportAction]
+ */
+function getDefaultRenderedReportActionItemSingle(shouldShowSubscriptAvatar = true, report = null, reportAction = null) {
+ const currentReport = report || getFakeReport();
+ const currentReportAction = reportAction || getFakeAdvancedReportAction();
+
+ internalRender(
+ ,
+ );
+}
+
+/**
+ * @param {Boolean} shouldShowSubscriptAvatar
+ * @param {Object} report
+ * @param {Object} reportAction
+ * @returns {JSX.Element}
+ */
+function MockedReportActionItemSingle({shouldShowSubscriptAvatar, report, reportAction}) {
+ const personalDetailsList = {
+ [reportAction.actorAccountID]: {
+ accountID: reportAction.actorAccountID,
+ login: 'email1@test.com',
+ displayName: 'Email One',
+ avatar: 'https://example.com/avatar.png',
+ firstName: 'One',
+ },
+ };
+
+ return (
+
+
+
+ );
+}
+
+MockedReportActionItemSingle.propTypes = {
+ shouldShowSubscriptAvatar: PropTypes.bool,
+ report: reportPropTypes,
+ reportAction: PropTypes.shape(reportActionPropTypes),
+};
+
+MockedReportActionItemSingle.defaultProps = {
+ shouldShowSubscriptAvatar: true,
+ report: null,
+ reportAction: null,
+};
+
+export {
+ fakePersonalDetails,
+ getDefaultRenderedSidebarLinks,
+ getAdvancedFakeReport,
+ getFakeReport,
+ getFakeReportAction,
+ MockedSidebarLinks,
+ getDefaultRenderedReportActionItemSingle,
+ MockedReportActionItemSingle,
+ getFakeReportWithPolicy,
+ getFakePolicy,
+ getFakeAdvancedReportAction,
+};
diff --git a/tests/utils/PusherHelper.js b/tests/utils/PusherHelper.js
index b763f4ebb28f..3d0ce1404a91 100644
--- a/tests/utils/PusherHelper.js
+++ b/tests/utils/PusherHelper.js
@@ -1,7 +1,7 @@
-import * as Pusher from '../../src/libs/Pusher/pusher';
-import PusherConnectionManager from '../../src/libs/PusherConnectionManager';
import CONFIG from '../../src/CONFIG';
import CONST from '../../src/CONST';
+import * as Pusher from '../../src/libs/Pusher/pusher';
+import PusherConnectionManager from '../../src/libs/PusherConnectionManager';
const CHANNEL_NAME = `${CONST.PUSHER.PRIVATE_USER_CHANNEL_PREFIX}1${CONFIG.PUSHER.SUFFIX}`;
diff --git a/tests/utils/TestHelper.js b/tests/utils/TestHelper.js
index 4c658f004894..03f5416a92fb 100644
--- a/tests/utils/TestHelper.js
+++ b/tests/utils/TestHelper.js
@@ -1,12 +1,12 @@
-import _ from 'underscore';
-import Onyx from 'react-native-onyx';
import Str from 'expensify-common/lib/str';
+import Onyx from 'react-native-onyx';
+import _ from 'underscore';
import CONST from '../../src/CONST';
import * as Session from '../../src/libs/actions/Session';
import HttpUtils from '../../src/libs/HttpUtils';
+import * as NumberUtils from '../../src/libs/NumberUtils';
import ONYXKEYS from '../../src/ONYXKEYS';
import waitForBatchedUpdates from './waitForBatchedUpdates';
-import * as NumberUtils from '../../src/libs/NumberUtils';
/**
* @param {String} login
diff --git a/tests/utils/bumpVersion.mjs b/tests/utils/bumpVersion.mjs
index e9ab115382ce..19471ee7f905 100644
--- a/tests/utils/bumpVersion.mjs
+++ b/tests/utils/bumpVersion.mjs
@@ -1,5 +1,4 @@
#!/usr/bin/env node
-
import {incrementVersion} from '../../.github/libs/versionUpdater.js';
const version = process.argv[2];
diff --git a/tests/utils/getPreviousVersion.mjs b/tests/utils/getPreviousVersion.mjs
index fb4acd625070..31ca672776fa 100644
--- a/tests/utils/getPreviousVersion.mjs
+++ b/tests/utils/getPreviousVersion.mjs
@@ -1,5 +1,4 @@
#!/usr/bin/env node
-
import {getPreviousVersion} from '../../.github/libs/versionUpdater.js';
const currentVersion = process.argv[2];
diff --git a/tests/utils/getPullRequestsMergedBetween.mjs b/tests/utils/getPullRequestsMergedBetween.mjs
index 05dedaa3e4f1..0afb1499e67f 100755
--- a/tests/utils/getPullRequestsMergedBetween.mjs
+++ b/tests/utils/getPullRequestsMergedBetween.mjs
@@ -1,5 +1,4 @@
#!/usr/bin/env node
-
import GitUtils from '../../.github/libs/GitUtils.js';
const fromRef = process.argv[2];
diff --git a/tests/utils/waitForBatchedUpdates.js b/tests/utils/waitForBatchedUpdates.js
index 2c4dbec250bc..c9d7a99fa1fb 100644
--- a/tests/utils/waitForBatchedUpdates.js
+++ b/tests/utils/waitForBatchedUpdates.js
@@ -1,4 +1,5 @@
import getIsUsingFakeTimers from './getIsUsingFakeTimers';
+
/**
* Method which waits for all asynchronous JS to stop executing before proceeding. This helps test things like actions
* that expect some Onyx value to be available. This way we do not have to explicitly wait for an action to finish
diff --git a/tsconfig.json b/tsconfig.json
index 0c88512b9749..151087fb1321 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -30,7 +30,20 @@
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
- "incremental": true
+ "incremental": true,
+ "baseUrl": ".",
+ "paths": {
+ "@assets/*": ["./assets/*"],
+ "@components/*": ["./src/components/*"],
+ "@hooks/*": ["./src/hooks/*"],
+ "@libs/*": ["./src/libs/*"],
+ "@navigation/*": ["./src/libs/Navigation/*"],
+ "@pages/*": ["./src/pages/*"],
+ "@styles/*": ["./src/styles/*"],
+ // This path is provide alias for files like `ONYXKEYS` and `CONST`.
+ "@src/*": ["./src/*"],
+ "@userActions/*": ["./src/libs/actions/*"]
+ }
},
"exclude": ["**/node_modules/*", "**/dist/*", ".github/actions/**/index.js", "**/docs/*"],
"include": ["src", "desktop", "web", "docs", "assets", "config", "tests", "jest", "__mocks__", ".github/**/*", ".storybook/**/*"]
diff --git a/wdyr.js b/wdyr.js
index 5f790b922d9e..ad1edaa5a075 100644
--- a/wdyr.js
+++ b/wdyr.js
@@ -1,8 +1,7 @@
// Implements Why Did You Render (WDYR) in Dev
-
+import lodashGet from 'lodash/get';
import React from 'react';
import Config from 'react-native-config';
-import lodashGet from 'lodash/get';
const useWDYR = lodashGet(Config, 'USE_WDYR') === 'true';
diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png
index 625b519e2cfa..3ddaf55904fb 100644
Binary files a/web/apple-touch-icon.png and b/web/apple-touch-icon.png differ
diff --git a/web/favicon-unread.png b/web/favicon-unread.png
index bc0cfc410696..d4c389786bb8 100644
Binary files a/web/favicon-unread.png and b/web/favicon-unread.png differ
diff --git a/web/favicon.png b/web/favicon.png
index b5ec8b935952..77913bafc471 100644
Binary files a/web/favicon.png and b/web/favicon.png differ
diff --git a/web/og-preview-image.png b/web/og-preview-image.png
index 00bccd247475..52bd5a54a480 100644
Binary files a/web/og-preview-image.png and b/web/og-preview-image.png differ
diff --git a/web/storybook-example.png b/web/storybook-example.png
index 448d9f89be23..64d7a988b4ad 100644
Binary files a/web/storybook-example.png and b/web/storybook-example.png differ