diff --git a/.github/ISSUE_TEMPLATE/Accessibility.md b/.github/ISSUE_TEMPLATE/Accessibility.md index 1323e2c17e78..97fc17d28a94 100644 --- a/.github/ISSUE_TEMPLATE/Accessibility.md +++ b/.github/ISSUE_TEMPLATE/Accessibility.md @@ -35,12 +35,12 @@ What can we do to fix the issue? Check off any platforms that are affected by this issue ---> Which of our officially supported platforms is this issue occurring on? Please only tick the box if you have provided a screen-recording in the thread for each platform: -- [ ] Android / native -- [ ] Android / Chrome -- [ ] iOS / native -- [ ] iOS / Safari -- [ ] MacOS / Chrome / Safari -- [ ] MacOS / Desktop +- [ ] Android: Native +- [ ] Android: mWeb Chrome +- [ ] iOS: Native +- [ ] iOS: mWeb Safari +- [ ] MacOS: Chrome / Safari +- [ ] MacOS: Desktop **Version Number:** **Reproducible in staging?:** diff --git a/.github/ISSUE_TEMPLATE/Performance.md b/.github/ISSUE_TEMPLATE/Performance.md index 67b2e6971874..bbb729e8af31 100644 --- a/.github/ISSUE_TEMPLATE/Performance.md +++ b/.github/ISSUE_TEMPLATE/Performance.md @@ -28,12 +28,12 @@ Note: These should be the same as the benchmarks collected before any changes. Check off any platforms that are affected by this issue ---> Which of our officially supported platforms is this issue occurring on? -- [ ] Android / native -- [ ] Android / Chrome -- [ ] iOS / native -- [ ] iOS / Safari -- [ ] MacOS / Chrome / Safari -- [ ] MacOS / Desktop +- [ ] Android: Native +- [ ] Android: mWeb Chrome +- [ ] iOS: Native +- [ ] iOS: mWeb Safari +- [ ] MacOS: Chrome / Safari +- [ ] MacOS: Desktop **Version Number:** **Reproducible in staging?:** diff --git a/.github/ISSUE_TEMPLATE/Standard.md b/.github/ISSUE_TEMPLATE/Standard.md index 39d1c38fa56f..5e0e3633f3bc 100644 --- a/.github/ISSUE_TEMPLATE/Standard.md +++ b/.github/ISSUE_TEMPLATE/Standard.md @@ -7,6 +7,16 @@ labels: Bug, Daily If you haven’t already, check out our [contributing guidelines](https://github.com/Expensify/ReactNativeChat/blob/main/contributingGuides/CONTRIBUTING.md) for onboarding and email contributors@expensify.com to request to join our Slack channel! ___ +**Version Number:** +**Reproducible in staging?:** +**Reproducible in production?:** +**If this was caught during regression testing, add the test name, ID and link from TestRail:** +**Email or phone of affected tester (no customers):** +**Logs:** https://stackoverflow.com/c/expensify/questions/4856 +**Expensify/Expensify Issue URL:** +**Issue reported by:** +**Slack conversation:** + ## Action Performed: Break down in numbered steps @@ -24,22 +34,54 @@ Can the user still use Expensify without this being fixed? Have you informed the Check off any platforms that are affected by this issue ---> Which of our officially supported platforms is this issue occurring on? -- [ ] Android / native -- [ ] Android / Chrome -- [ ] iOS / native -- [ ] iOS / Safari -- [ ] MacOS / Chrome / Safari -- [ ] MacOS / Desktop +- [ ] Android: Native +- [ ] Android: mWeb Chrome +- [ ] iOS: Native +- [ ] iOS: mWeb Safari +- [ ] MacOS: Chrome / Safari +- [ ] MacOS: Desktop -**Version Number:** -**Reproducible in staging?:** -**Reproducible in production?:** -**If this was caught during regression testing, add the test name, ID and link from TestRail:** -**Email or phone of affected tester (no customers):** -**Logs:** https://stackoverflow.com/c/expensify/questions/4856 -**Notes/Photos/Videos:** Any additional supporting documentation -**Expensify/Expensify Issue URL:** -**Issue reported by:** -**Slack conversation:** +## Screenshots/Videos +
+Android: Native + + + +
+ +
+Android: mWeb Chrome + + + +
+ +
+iOS: Native + + + +
+ +
+iOS: mWeb Safari + + + +
+ +
+MacOS: Chrome / Safari + + + +
+ +
+MacOS: Desktop + + + +
[View all open jobs on GitHub](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 800888580518..0396a7543b50 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -70,12 +70,12 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c - [ ] I tested this PR with a [High Traffic account](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#high-traffic-accounts) against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability). - [ ] I included screenshots or videos for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms) - [ ] I ran the tests on **all platforms** & verified they passed on: - - [ ] Android / native - - [ ] Android / Chrome - - [ ] iOS / native - - [ ] iOS / Safari - - [ ] MacOS / Chrome / Safari - - [ ] MacOS / Desktop + - [ ] Android: Native + - [ ] Android: mWeb Chrome + - [ ] iOS: Native + - [ ] iOS: mWeb Safari + - [ ] MacOS: Chrome / Safari + - [ ] MacOS: Desktop - [ ] I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed) - [ ] I followed proper code patterns (see [Reviewing the code](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md#reviewing-the-code)) - [ ] I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. `toggleReport` and not `onIconClick`) @@ -120,42 +120,42 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c ### 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/android/app/build.gradle b/android/app/build.gradle index 148a46ddc00d..2470ef0038c2 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 1001037903 - versionName "1.3.79-3" + versionCode 1001038000 + versionName "1.3.80-0" } flavorDimensions "default" diff --git a/assets/emojis/es.js b/assets/emojis/es.js index c38aec7aa754..fda12f5f127c 100644 --- a/assets/emojis/es.js +++ b/assets/emojis/es.js @@ -6208,1044 +6208,1044 @@ const esEmojis = { keywords: ['Bandera'], }, '🇦🇩': { - name: 'bandera-ad', - keywords: ['Bandera'], + name: 'andorra', + keywords: ['bandera', 'bandera-ad'], }, '🇦🇪': { - name: 'bandera-ae', - keywords: ['Bandera'], + name: 'emiratos_árabes_unidos', + keywords: ['bandera', 'bandera-ae'], }, '🇦🇫': { - name: 'bandera-af', - keywords: ['Bandera'], + name: 'afganistán', + keywords: ['bandera', 'bandera-af'], }, '🇦🇬': { - name: 'bandera-ag', - keywords: ['Bandera'], + name: 'antigua_y_barbuda', + keywords: ['bandera', 'bandera-ag'], }, '🇦🇮': { - name: 'bandera-ai', - keywords: ['Bandera'], + name: 'anguila', + keywords: ['bandera', 'bandera-ai'], }, '🇦🇱': { - name: 'bandera-al', - keywords: ['Bandera'], + name: 'albania', + keywords: ['bandera', 'bandera-al'], }, '🇦🇲': { - name: 'bandera-am', - keywords: ['Bandera'], + name: 'armenia', + keywords: ['bandera', 'bandera-am'], }, '🇦🇴': { - name: 'bandera-ao', - keywords: ['Bandera'], + name: 'angola', + keywords: ['bandera', 'bandera-ao'], }, '🇦🇶': { - name: 'bandera-aq', - keywords: ['Bandera'], + name: 'antártida', + keywords: ['bandera', 'bandera-aq'], }, '🇦🇷': { - name: 'bandera-ar', - keywords: ['Bandera'], + name: 'argentina', + keywords: ['bandera', 'bandera-ar'], }, '🇦🇸': { - name: 'bandera-as', - keywords: ['Bandera'], + name: 'samoa_americana', + keywords: ['bandera', 'bandera-as'], }, '🇦🇹': { - name: 'bandera-at', - keywords: ['Bandera'], + name: 'austria', + keywords: ['bandera', 'bandera-at'], }, '🇦🇺': { - name: 'bandera-au', - keywords: ['Bandera'], + name: 'australia', + keywords: ['bandera', 'bandera-au'], }, '🇦🇼': { - name: 'bandera-aw', - keywords: ['Bandera'], + name: 'aruba', + keywords: ['bandera', 'bandera-aw'], }, '🇦🇽': { - name: 'bandera-ax', - keywords: ['Bandera'], + name: 'islas_de_åland', + keywords: ['bandera', 'bandera-ax'], }, '🇦🇿': { - name: 'bandera-az', - keywords: ['Bandera'], + name: 'azerbaiyán', + keywords: ['bandera', 'bandera-az'], }, '🇧🇦': { - name: 'bandera-ba', - keywords: ['Bandera'], + name: 'bosnia_y_herzegovina', + keywords: ['bandera', 'bandera-ba'], }, '🇧🇧': { - name: 'bandera-bb', - keywords: ['Bandera'], + name: 'barbados', + keywords: ['bandera', 'bandera-bb'], }, '🇧🇩': { - name: 'bandera-bd', - keywords: ['Bandera'], + name: 'bangladesh', + keywords: ['bandera', 'bandera-bd'], }, '🇧🇪': { - name: 'bandera-be', - keywords: ['Bandera'], + name: 'bélgica', + keywords: ['bandera', 'bandera-be'], }, '🇧🇫': { - name: 'bandera-bf', - keywords: ['Bandera'], + name: 'burkina_faso', + keywords: ['bandera', 'bandera-bf'], }, '🇧🇬': { - name: 'bandera-bg', - keywords: ['Bandera'], + name: 'bulgaria', + keywords: ['bandera', 'bandera-bg'], }, '🇧🇭': { - name: 'bandera-bh', - keywords: ['Bandera'], + name: 'bahrein', + keywords: ['bandera', 'bandera-bh'], }, '🇧🇮': { - name: 'bandera-bi', - keywords: ['Bandera'], + name: 'burundi', + keywords: ['bandera', 'bandera-bi'], }, '🇧🇯': { - name: 'bandera-bj', - keywords: ['Bandera'], + name: 'benin', + keywords: ['bandera', 'bandera-bj'], }, '🇧🇱': { - name: 'bandera-bl', - keywords: ['Bandera'], + name: 'san_bartolomé', + keywords: ['bandera', 'bandera-bl'], }, '🇧🇲': { - name: 'bandera-bm', - keywords: ['Bandera'], + name: 'islas_bermudas', + keywords: ['bandera', 'bandera-bm'], }, '🇧🇳': { - name: 'bandera-bn', - keywords: ['Bandera'], + name: 'brunéi', + keywords: ['bandera', 'bandera-bn'], }, '🇧🇴': { - name: 'bandera-bo', - keywords: ['Bandera'], + name: 'bolivia', + keywords: ['bandera', 'bandera-bo'], }, '🇧🇶': { - name: 'bandera-bq', - keywords: ['Bandera'], + name: 'bonaire,_san_eustaquio_y_saba', + keywords: ['bandera', 'bandera-bq'], }, '🇧🇷': { - name: 'bandera-br', - keywords: ['Bandera'], + name: 'brazil', + keywords: ['bandera', 'bandera-br'], }, '🇧🇸': { - name: 'bandera-bs', - keywords: ['Bandera'], + name: 'bahamas', + keywords: ['bandera', 'bandera-bs'], }, '🇧🇹': { - name: 'bandera-bt', - keywords: ['Bandera'], + name: 'bhután', + keywords: ['bandera', 'bandera-bt'], }, '🇧🇻': { name: 'bandera-bv', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-bv'], }, '🇧🇼': { - name: 'bandera-bw', - keywords: ['Bandera'], + name: 'botsuana', + keywords: ['bandera', 'bandera-bw'], }, '🇧🇾': { - name: 'bandera-by', - keywords: ['Bandera'], + name: 'bielorrusia', + keywords: ['bandera', 'bandera-by'], }, '🇧🇿': { - name: 'bandera-bz', - keywords: ['Bandera'], + name: 'belice', + keywords: ['bandera', 'bandera-bz'], }, '🇨🇦': { - name: 'bandera-ca', - keywords: ['Bandera'], + name: 'canadá', + keywords: ['bandera', 'bandera-ca'], }, '🇨🇨': { - name: 'bandera-cc', - keywords: ['Bandera'], + name: 'islas_cocos_(keeling)', + keywords: ['bandera', 'bandera-cc'], }, '🇨🇩': { - name: 'bandera-cd', - keywords: ['Bandera'], + name: 'república_democrática_del_congo', + keywords: ['bandera', 'bandera-cd'], }, '🇨🇫': { - name: 'bandera-cf', - keywords: ['Bandera'], + name: 'república_centroafricana', + keywords: ['bandera', 'bandera-cf'], }, '🇨🇬': { - name: 'bandera-cg', - keywords: ['Bandera'], + name: 'república_del_congo', + keywords: ['bandera', 'bandera-cg'], }, '🇨🇭': { - name: 'bandera-ch', - keywords: ['Bandera'], + name: 'suiza', + keywords: ['bandera', 'bandera-ch'], }, '🇨🇮': { - name: 'bandera-ci', - keywords: ['Bandera'], + name: 'costa_de_marfil', + keywords: ['bandera', 'bandera-ci'], }, '🇨🇰': { - name: 'bandera-ck', - keywords: ['Bandera'], + name: 'islas_cook', + keywords: ['bandera', 'bandera-ck'], }, '🇨🇱': { - name: 'bandera-cl', - keywords: ['Bandera'], + name: 'chile', + keywords: ['bandera', 'bandera-cl'], }, '🇨🇲': { - name: 'bandera-cm', - keywords: ['Bandera'], + name: 'camerún', + keywords: ['bandera', 'bandera-cm'], }, '🇨🇳': { - name: 'cn', - keywords: ['Bandera'], + name: 'china', + keywords: ['bandera', 'bandera-cn'], }, '🇨🇴': { - name: 'bandera-co', - keywords: ['Bandera'], + name: 'colombia', + keywords: ['bandera', 'bandera-co'], }, '🇨🇵': { name: 'bandera-cp', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-cp'], }, '🇨🇷': { - name: 'bandera-cr', - keywords: ['Bandera'], + name: 'costa_rica', + keywords: ['bandera', 'bandera-cr'], }, '🇨🇺': { - name: 'bandera-cu', - keywords: ['Bandera'], + name: 'cuba', + keywords: ['bandera', 'bandera-cu'], }, '🇨🇻': { - name: 'bandera-cv', - keywords: ['Bandera'], + name: 'cabo_verde', + keywords: ['bandera', 'bandera-cv'], }, '🇨🇼': { - name: 'bandera-cw', - keywords: ['Bandera'], + name: 'curazao', + keywords: ['bandera', 'bandera-cw'], }, '🇨🇽': { - name: 'bandera-cx', - keywords: ['Bandera'], + name: 'isla_de_navidad', + keywords: ['bandera', 'bandera-cx'], }, '🇨🇾': { - name: 'bandera-cy', - keywords: ['Bandera'], + name: 'chipre', + keywords: ['bandera', 'bandera-cy'], }, '🇨🇿': { - name: 'bandera-cz', - keywords: ['Bandera'], + name: 'república_checa', + keywords: ['bandera', 'bandera-cz'], }, '🇩🇪': { - name: 'de', - keywords: ['Bandera'], + name: 'alemania', + keywords: ['bandera', 'bandera-de'], }, '🇩🇬': { name: 'bandera-dg', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-dg'], }, '🇩🇯': { - name: 'bandera-dj', - keywords: ['Bandera'], + name: 'yibuti', + keywords: ['bandera', 'bandera-dj'], }, '🇩🇰': { - name: 'bandera-dk', - keywords: ['Bandera'], + name: 'dinamarca', + keywords: ['bandera', 'bandera-dk'], }, '🇩🇲': { - name: 'bandera-dm', - keywords: ['Bandera'], + name: 'dominica', + keywords: ['bandera', 'bandera-dm'], }, '🇩🇴': { - name: 'bandera-do', - keywords: ['Bandera'], + name: 'república_dominicana', + keywords: ['bandera', 'bandera-do'], }, '🇩🇿': { - name: 'bandera-dz', - keywords: ['Bandera'], + name: 'argelia', + keywords: ['bandera', 'bandera-dz'], }, '🇪🇦': { name: 'bandera-ea', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-ea'], }, '🇪🇨': { - name: 'bandera-ec', - keywords: ['Bandera'], + name: 'ecuador', + keywords: ['bandera', 'bandera-ec'], }, '🇪🇪': { - name: 'bandera-ee', - keywords: ['Bandera'], + name: 'estonia', + keywords: ['bandera', 'bandera-ee'], }, '🇪🇬': { - name: 'bandera-eg', - keywords: ['Bandera'], + name: 'egipto', + keywords: ['bandera', 'bandera-eg'], }, '🇪🇭': { - name: 'bandera-eh', - keywords: ['Bandera'], + name: 'sahara_occidental', + keywords: ['bandera', 'bandera-eh'], }, '🇪🇷': { - name: 'bandera-er', - keywords: ['Bandera'], + name: 'eritrea', + keywords: ['bandera', 'bandera-er'], }, '🇪🇸': { - name: 'es', - keywords: ['Bandera'], + name: 'españa', + keywords: ['bandera', 'bandera-es'], }, '🇪🇹': { - name: 'bandera-et', - keywords: ['Bandera'], + name: 'etiopía', + keywords: ['bandera', 'bandera-et'], }, '🇪🇺': { name: 'bandera-eu', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-eu'], }, '🇫🇮': { - name: 'bandera-fi', - keywords: ['Bandera'], + name: 'finlandia', + keywords: ['bandera', 'bandera-fi'], }, '🇫🇯': { - name: 'bandera-fj', - keywords: ['Bandera'], + name: 'fiyi', + keywords: ['bandera', 'bandera-fj'], }, '🇫🇰': { - name: 'bandera-fk', - keywords: ['Bandera'], + name: 'islas_malvinas', + keywords: ['bandera', 'bandera-fk'], }, '🇫🇲': { - name: 'bandera-fm', - keywords: ['Bandera'], + name: 'micronesia', + keywords: ['bandera', 'bandera-fm'], }, '🇫🇴': { - name: 'bandera-fo', - keywords: ['Bandera'], + name: 'islas_feroe', + keywords: ['bandera', 'bandera-fo'], }, '🇫🇷': { - name: 'fr', - keywords: ['Bandera'], + name: 'francia', + keywords: ['bandera', 'bandera-fr'], }, '🇬🇦': { - name: 'bandera-ga', - keywords: ['Bandera'], + name: 'gabón', + keywords: ['bandera', 'bandera-ga'], }, '🇬🇧': { - name: 'gb', - keywords: ['Bandera'], + name: 'reino_unido', + keywords: ['bandera', 'bandera-gb'], }, '🇬🇩': { - name: 'bandera-gd', - keywords: ['Bandera'], + name: 'granada', + keywords: ['bandera', 'bandera-gd'], }, '🇬🇪': { - name: 'bandera-ge', - keywords: ['Bandera'], + name: 'georgia', + keywords: ['bandera', 'bandera-ge'], }, '🇬🇫': { - name: 'bandera-gf', - keywords: ['Bandera'], + name: 'guayana_francesa', + keywords: ['bandera', 'bandera-gf'], }, '🇬🇬': { - name: 'bandera-gg', - keywords: ['Bandera'], + name: 'guernsey', + keywords: ['bandera', 'bandera-gg'], }, '🇬🇭': { - name: 'bandera-gh', - keywords: ['Bandera'], + name: 'ghana', + keywords: ['bandera', 'bandera-gh'], }, '🇬🇮': { - name: 'bandera-gi', - keywords: ['Bandera'], + name: 'gibraltar', + keywords: ['bandera', 'bandera-gi'], }, '🇬🇱': { - name: 'bandera-gl', - keywords: ['Bandera'], + name: 'groenlandia', + keywords: ['bandera', 'bandera-gl'], }, '🇬🇲': { - name: 'bandera-gm', - keywords: ['Bandera'], + name: 'gambia', + keywords: ['bandera', 'bandera-gm'], }, '🇬🇳': { - name: 'bandera-gn', - keywords: ['Bandera'], + name: 'guinea', + keywords: ['bandera', 'bandera-gn'], }, '🇬🇵': { - name: 'bandera-gp', - keywords: ['Bandera'], + name: 'guadeloupe', + keywords: ['bandera', 'bandera-gp'], }, '🇬🇶': { - name: 'bandera-gq', - keywords: ['Bandera'], + name: 'guinea_ecuatorial', + keywords: ['bandera', 'bandera-gq'], }, '🇬🇷': { - name: 'bandera-gr', - keywords: ['Bandera'], + name: 'greece', + keywords: ['bandera', 'bandera-gr'], }, '🇬🇸': { - name: 'bandera-gs', - keywords: ['Bandera'], + name: 'islas_georgias_del_sur_y_sandwich_del_sur', + keywords: ['bandera', 'bandera-gs'], }, '🇬🇹': { - name: 'bandera-gt', - keywords: ['Bandera'], + name: 'guatemala', + keywords: ['bandera', 'bandera-gt'], }, '🇬🇺': { - name: 'bandera-gu', - keywords: ['Bandera'], + name: 'guam', + keywords: ['bandera', 'bandera-gu'], }, '🇬🇼': { - name: 'bandera-gw', - keywords: ['Bandera'], + name: 'guinea-bissau', + keywords: ['bandera', 'bandera-gw'], }, '🇬🇾': { - name: 'bandera-gy', - keywords: ['Bandera'], + name: 'guyana', + keywords: ['bandera', 'bandera-gy'], }, '🇭🇰': { - name: 'bandera-hk', - keywords: ['Bandera'], + name: 'hong_kong', + keywords: ['bandera', 'bandera-hk'], }, '🇭🇲': { name: 'bandera-hm', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-hm'], }, '🇭🇳': { - name: 'bandera-hn', - keywords: ['Bandera'], + name: 'honduras', + keywords: ['bandera', 'bandera-hn'], }, '🇭🇷': { - name: 'bandera-hr', - keywords: ['Bandera'], + name: 'croacia', + keywords: ['bandera', 'bandera-hr'], }, '🇭🇹': { - name: 'bandera-ht', - keywords: ['Bandera'], + name: 'haiti', + keywords: ['bandera', 'bandera-ht'], }, '🇭🇺': { - name: 'bandera-hu', - keywords: ['Bandera'], + name: 'hungría', + keywords: ['bandera', 'bandera-hu'], }, '🇮🇨': { name: 'bandera-ic', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-ic'], }, '🇮🇩': { - name: 'bandera-id', - keywords: ['Bandera'], + name: 'indonesia', + keywords: ['bandera', 'bandera-id'], }, '🇮🇪': { - name: 'bandera-ie', - keywords: ['Bandera'], + name: 'irlanda', + keywords: ['bandera', 'bandera-ie'], }, '🇮🇱': { - name: 'bandera-il', - keywords: ['Bandera'], + name: 'israel', + keywords: ['bandera', 'bandera-il'], }, '🇮🇲': { - name: 'bandera-im', - keywords: ['Bandera'], + name: 'isla_de_man', + keywords: ['bandera', 'bandera-im'], }, '🇮🇳': { - name: 'bandera-in', - keywords: ['Bandera'], + name: 'india', + keywords: ['bandera', 'bandera-in'], }, '🇮🇴': { - name: 'bandera-io', - keywords: ['Bandera'], + name: 'territorio_británico_del_océano_índico', + keywords: ['bandera', 'bandera-io'], }, '🇮🇶': { - name: 'bandera-iq', - keywords: ['Bandera'], + name: 'irak', + keywords: ['bandera', 'bandera-iq'], }, '🇮🇷': { - name: 'bandera-ir', - keywords: ['Bandera'], + name: 'irán', + keywords: ['bandera', 'bandera-ir'], }, '🇮🇸': { - name: 'bandera-is', - keywords: ['Bandera'], + name: 'islandia', + keywords: ['bandera', 'bandera-is'], }, '🇮🇹': { - name: 'it', - keywords: ['Bandera'], + name: 'italia', + keywords: ['bandera', 'bandera-it'], }, '🇯🇪': { - name: 'bandera-je', - keywords: ['Bandera'], + name: 'jersey', + keywords: ['bandera', 'bandera-je'], }, '🇯🇲': { - name: 'bandera-jm', - keywords: ['Bandera'], + name: 'jamaica', + keywords: ['bandera', 'bandera-jm'], }, '🇯🇴': { - name: 'bandera-jo', - keywords: ['Bandera'], + name: 'jordania', + keywords: ['bandera', 'bandera-jo'], }, '🇯🇵': { - name: 'jp', - keywords: ['Bandera'], + name: 'japón', + keywords: ['bandera', 'bandera-jp'], }, '🇰🇪': { - name: 'bandera-ke', - keywords: ['Bandera'], + name: 'kenia', + keywords: ['bandera', 'bandera-ke'], }, '🇰🇬': { - name: 'bandera-kg', - keywords: ['Bandera'], + name: 'kirguistán', + keywords: ['bandera', 'bandera-kg'], }, '🇰🇭': { - name: 'bandera-kh', - keywords: ['Bandera'], + name: 'camboya', + keywords: ['bandera', 'bandera-kh'], }, '🇰🇮': { name: 'bandera-kl', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-kl'], }, '🇰🇲': { - name: 'bandera-km', - keywords: ['Bandera'], + name: 'comoras', + keywords: ['bandera', 'bandera-km'], }, '🇰🇳': { - name: 'bandera-kn', - keywords: ['Bandera'], + name: 'san_cristóbal_y_nieves', + keywords: ['bandera', 'bandera-kn'], }, '🇰🇵': { - name: 'bandera-kp', - keywords: ['Bandera'], + name: 'corea_del_norte', + keywords: ['bandera', 'bandera-kp'], }, '🇰🇷': { - name: 'kr', - keywords: ['Bandera'], + name: 'corea_del_sur', + keywords: ['bandera', 'bandera-kr'], }, '🇰🇼': { - name: 'bandera-kw', - keywords: ['Bandera'], + name: 'kuwait', + keywords: ['bandera', 'bandera-kw'], }, '🇰🇾': { - name: 'bandera-ky', - keywords: ['Bandera'], + name: 'islas_caimán', + keywords: ['bandera', 'bandera-ky'], }, '🇰🇿': { - name: 'bandera-kz', - keywords: ['Bandera'], + name: 'kazajistán', + keywords: ['bandera', 'bandera-kz'], }, '🇱🇦': { - name: 'bandera-la', - keywords: ['Bandera'], + name: 'laos', + keywords: ['bandera', 'bandera-la'], }, '🇱🇧': { - name: 'bandera-lb', - keywords: ['Bandera'], + name: 'líbano', + keywords: ['bandera', 'bandera-lb'], }, '🇱🇨': { - name: 'bandera-lc', - keywords: ['Bandera'], + name: 'santa_lucía', + keywords: ['bandera', 'bandera-lc'], }, '🇱🇮': { - name: 'bandera-li', - keywords: ['Bandera'], + name: 'liechtenstein', + keywords: ['bandera', 'bandera-li'], }, '🇱🇰': { - name: 'bandera-lk', - keywords: ['Bandera'], + name: 'sri_lanka', + keywords: ['bandera', 'bandera-lk'], }, '🇱🇷': { - name: 'bandera-lr', - keywords: ['Bandera'], + name: 'liberia', + keywords: ['bandera', 'bandera-lr'], }, '🇱🇸': { - name: 'bandera-ls', - keywords: ['Bandera'], + name: 'lesoto', + keywords: ['bandera', 'bandera-ls'], }, '🇱🇹': { - name: 'bandera-lt', - keywords: ['Bandera'], + name: 'lituania', + keywords: ['bandera', 'bandera-lt'], }, '🇱🇺': { - name: 'bandera-lu', - keywords: ['Bandera'], + name: 'luxemburgo', + keywords: ['bandera', 'bandera-lu'], }, '🇱🇻': { - name: 'bandera-lv', - keywords: ['Bandera'], + name: 'letonia', + keywords: ['bandera', 'bandera-lv'], }, '🇱🇾': { - name: 'bandera-ly', - keywords: ['Bandera'], + name: 'libia', + keywords: ['bandera', 'bandera-ly'], }, '🇲🇦': { - name: 'bandera-ma', - keywords: ['Bandera'], + name: 'marruecos', + keywords: ['bandera', 'bandera-ma'], }, '🇲🇨': { - name: 'bandera-mc', - keywords: ['Bandera'], + name: 'mónaco', + keywords: ['bandera', 'bandera-mc'], }, '🇲🇩': { - name: 'bandera-md', - keywords: ['Bandera'], + name: 'moldavia', + keywords: ['bandera', 'bandera-md'], }, '🇲🇪': { - name: 'bandera-me', - keywords: ['Bandera'], + name: 'montenegro', + keywords: ['bandera', 'bandera-me'], }, '🇲🇫': { - name: 'bandera-mf', - keywords: ['Bandera'], + name: 'san_martín_(francia)', + keywords: ['bandera', 'bandera-mf'], }, '🇲🇬': { - name: 'bandera-mg', - keywords: ['Bandera'], + name: 'madagascar', + keywords: ['bandera', 'bandera-mg'], }, '🇲🇭': { - name: 'bandera-mh', - keywords: ['Bandera'], + name: 'islas_marshall', + keywords: ['bandera', 'bandera-mh'], }, '🇲🇰': { - name: 'bandera-mk', - keywords: ['Bandera'], + name: 'macedônia', + keywords: ['bandera', 'bandera-mk'], }, '🇲🇱': { - name: 'bandera-ml', - keywords: ['Bandera'], + name: 'mali', + keywords: ['bandera', 'bandera-ml'], }, '🇲🇲': { - name: 'bandera-mm', - keywords: ['Bandera'], + name: 'birmania', + keywords: ['bandera', 'bandera-mm'], }, '🇲🇳': { - name: 'bandera-mn', - keywords: ['Bandera'], + name: 'mongolia', + keywords: ['bandera', 'bandera-mn'], }, '🇲🇴': { - name: 'bandera-mo', - keywords: ['Bandera'], + name: 'macao', + keywords: ['bandera', 'bandera-mo'], }, '🇲🇵': { - name: 'bandera-mp', - keywords: ['Bandera'], + name: 'islas_marianas_del_norte', + keywords: ['bandera', 'bandera-mp'], }, '🇲🇶': { - name: 'bandera-mq', - keywords: ['Bandera'], + name: 'martinica', + keywords: ['bandera', 'bandera-mq'], }, '🇲🇷': { - name: 'bandera-mr', - keywords: ['Bandera'], + name: 'mauritania', + keywords: ['bandera', 'bandera-mr'], }, '🇲🇸': { - name: 'bandera-ms', - keywords: ['Bandera'], + name: 'montserrat', + keywords: ['bandera', 'bandera-ms'], }, '🇲🇹': { - name: 'bandera-mt', - keywords: ['Bandera'], + name: 'malta', + keywords: ['bandera', 'bandera-mt'], }, '🇲🇺': { - name: 'bandera-mu', - keywords: ['Bandera'], + name: 'mauritius', + keywords: ['bandera', 'bandera-mu'], }, '🇲🇻': { - name: 'bandera-mv', - keywords: ['Bandera'], + name: 'islas_maldivas', + keywords: ['bandera', 'bandera-mv'], }, '🇲🇼': { - name: 'bandera-mw', - keywords: ['Bandera'], + name: 'malawi', + keywords: ['bandera', 'bandera-mw'], }, '🇲🇽': { - name: 'bandera-mx', - keywords: ['Bandera'], + name: 'méxico', + keywords: ['bandera', 'bandera-mx'], }, '🇲🇾': { - name: 'bandera-my', - keywords: ['Bandera'], + name: 'malasia', + keywords: ['bandera', 'bandera-my'], }, '🇲🇿': { - name: 'bandera-mz', - keywords: ['Bandera'], + name: 'mozambique', + keywords: ['bandera', 'bandera-mz'], }, '🇳🇦': { - name: 'bandera-na', - keywords: ['Bandera'], + name: 'namibia', + keywords: ['bandera', 'bandera-na'], }, '🇳🇨': { - name: 'bandera-nc', - keywords: ['Bandera'], + name: 'nueva_caledonia', + keywords: ['bandera', 'bandera-nc'], }, '🇳🇪': { - name: 'bandera-ne', - keywords: ['Bandera'], + name: 'niger', + keywords: ['bandera', 'bandera-ne'], }, '🇳🇫': { - name: 'bandera-nf', - keywords: ['Bandera'], + name: 'isla_norfolk', + keywords: ['bandera', 'bandera-nf'], }, '🇳🇬': { - name: 'bandera-ng', - keywords: ['Bandera'], + name: 'nigeria', + keywords: ['bandera', 'bandera-ng'], }, '🇳🇮': { - name: 'bandera-ni', - keywords: ['Bandera'], + name: 'nicaragua', + keywords: ['bandera', 'bandera-ni'], }, '🇳🇱': { - name: 'bandera-nl', - keywords: ['Bandera'], + name: 'países_bajos', + keywords: ['bandera', 'bandera-nl'], }, '🇳🇴': { - name: 'bandera-no', - keywords: ['Bandera'], + name: 'noruega', + keywords: ['bandera', 'bandera-no'], }, '🇳🇵': { - name: 'bandera-np', - keywords: ['Bandera'], + name: 'nepal', + keywords: ['bandera', 'bandera-np'], }, '🇳🇷': { - name: 'bandera-nr', - keywords: ['Bandera'], + name: 'nauru', + keywords: ['bandera', 'bandera-nr'], }, '🇳🇺': { - name: 'bandera-nu', - keywords: ['Bandera'], + name: 'niue', + keywords: ['bandera', 'bandera-nu'], }, '🇳🇿': { - name: 'bandera-nz', - keywords: ['Bandera'], + name: 'nueva_zealand', + keywords: ['bandera', 'bandera-nz'], }, '🇴🇲': { - name: 'bandera-om', - keywords: ['Bandera'], + name: 'omán', + keywords: ['bandera', 'bandera-om'], }, '🇵🇦': { - name: 'bandera-pa', - keywords: ['Bandera'], + name: 'panamá', + keywords: ['bandera', 'bandera-pa'], }, '🇵🇪': { - name: 'bandera-pe', - keywords: ['Bandera'], + name: 'perú', + keywords: ['bandera', 'bandera-pe'], }, '🇵🇫': { - name: 'bandera-pf', - keywords: ['Bandera'], + name: 'polinesia_francesa', + keywords: ['bandera', 'bandera-pf'], }, '🇵🇬': { - name: 'bandera-pg', - keywords: ['Bandera'], + name: 'papúa_nueva_guinea', + keywords: ['bandera', 'bandera-pg'], }, '🇵🇭': { - name: 'bandera-ph', - keywords: ['Bandera'], + name: 'filipinas', + keywords: ['bandera', 'bandera-ph'], }, '🇵🇰': { - name: 'bandera-pk', - keywords: ['Bandera'], + name: 'pakistán', + keywords: ['bandera', 'bandera-pk'], }, '🇵🇱': { - name: 'bandera-pl', - keywords: ['Bandera'], + name: 'polonia', + keywords: ['bandera', 'bandera-pl'], }, '🇵🇲': { - name: 'bandera-pm', - keywords: ['Bandera'], + name: 'san_pedro_y_miquelón', + keywords: ['bandera', 'bandera-pm'], }, '🇵🇳': { - name: 'bandera-pn', - keywords: ['Bandera'], + name: 'islas_pitcairn', + keywords: ['bandera', 'bandera-pn'], }, '🇵🇷': { - name: 'bandera-pr', - keywords: ['Bandera'], + name: 'puerto_rico', + keywords: ['bandera', 'bandera-pr'], }, '🇵🇸': { - name: 'bandera-ps', - keywords: ['Bandera'], + name: 'palestina', + keywords: ['bandera', 'bandera-ps'], }, '🇵🇹': { - name: 'bandera-pt', - keywords: ['Bandera'], + name: 'portugal', + keywords: ['bandera', 'bandera-pt'], }, '🇵🇼': { - name: 'bandera-pw', - keywords: ['Bandera'], + name: 'palau', + keywords: ['bandera', 'bandera-pw'], }, '🇵🇾': { - name: 'bandera-py', - keywords: ['Bandera'], + name: 'paraguay', + keywords: ['bandera', 'bandera-py'], }, '🇶🇦': { - name: 'bandera-qa', - keywords: ['Bandera'], + name: 'qatar', + keywords: ['bandera', 'bandera-qa'], }, '🇷🇪': { - name: 'bandera-re', - keywords: ['Bandera'], + name: 'reunión', + keywords: ['bandera', 'bandera-re'], }, '🇷🇴': { - name: 'bandera-ro', - keywords: ['Bandera'], + name: 'rumanía', + keywords: ['bandera', 'bandera-ro'], }, '🇷🇸': { - name: 'bandera-rs', - keywords: ['Bandera'], + name: 'serbia', + keywords: ['bandera', 'bandera-rs'], }, '🇷🇺': { - name: 'ru', - keywords: ['Bandera'], + name: 'rusia', + keywords: ['bandera', 'bandera-ru'], }, '🇷🇼': { - name: 'bandera-rw', - keywords: ['Bandera'], + name: 'ruanda', + keywords: ['bandera', 'bandera-rw'], }, '🇸🇦': { - name: 'bandera-sa', - keywords: ['Bandera'], + name: 'arabia_saudita', + keywords: ['bandera', 'bandera-sa'], }, '🇸🇧': { - name: 'bandera-sb', - keywords: ['Bandera'], + name: 'islas_salomón', + keywords: ['bandera', 'bandera-sb'], }, '🇸🇨': { - name: 'bandera-sc', - keywords: ['Bandera'], + name: 'seychelles', + keywords: ['bandera', 'bandera-sc'], }, '🇸🇩': { - name: 'bandera-sd', - keywords: ['Bandera'], + name: 'sudán', + keywords: ['bandera', 'bandera-sd'], }, '🇸🇪': { - name: 'bandera-se', - keywords: ['Bandera'], + name: 'suecia', + keywords: ['bandera', 'bandera-se'], }, '🇸🇬': { - name: 'bandera-sg', - keywords: ['Bandera'], + name: 'singapur', + keywords: ['bandera', 'bandera-sg'], }, '🇸🇭': { - name: 'bandera-sh', - keywords: ['Bandera'], + name: 'santa_elena', + keywords: ['bandera', 'bandera-sh'], }, '🇸🇮': { - name: 'bandera-si', - keywords: ['Bandera'], + name: 'eslovenia', + keywords: ['bandera', 'bandera-si'], }, '🇸🇯': { - name: 'bandera-sj', - keywords: ['Bandera'], + name: 'svalbard_y_jan_mayen', + keywords: ['bandera', 'bandera-sj'], }, '🇸🇰': { - name: 'bandera-sk', - keywords: ['Bandera'], + name: 'eslovaquia', + keywords: ['bandera', 'bandera-sk'], }, '🇸🇱': { - name: 'bandera-sl', - keywords: ['Bandera'], + name: 'sierra_leona', + keywords: ['bandera', 'bandera-sl'], }, '🇸🇲': { - name: 'bandera-sm', - keywords: ['Bandera'], + name: 'san_marino', + keywords: ['bandera', 'bandera-sm'], }, '🇸🇳': { - name: 'bandera-sn', - keywords: ['Bandera'], + name: 'senegal', + keywords: ['bandera', 'bandera-sn'], }, '🇸🇴': { - name: 'bandera-so', - keywords: ['Bandera'], + name: 'somalia', + keywords: ['bandera', 'bandera-so'], }, '🇸🇷': { - name: 'bandera-sr', - keywords: ['Bandera'], + name: 'surinám', + keywords: ['bandera', 'bandera-sr'], }, '🇸🇸': { - name: 'bandera-ss', - keywords: ['Bandera'], + name: 'república_de_sudán_del_sur', + keywords: ['bandera', 'bandera-ss'], }, '🇸🇹': { - name: 'bandera-st', - keywords: ['Bandera'], + name: 'santo_tomé_y_príncipe', + keywords: ['bandera', 'bandera-st'], }, '🇸🇻': { - name: 'bandera-sv', - keywords: ['Bandera'], + name: 'el_salvador', + keywords: ['bandera', 'bandera-sv'], }, '🇸🇽': { - name: 'bandera-sx', - keywords: ['Bandera'], + name: 'sint_maarten', + keywords: ['bandera', 'bandera-sx'], }, '🇸🇾': { - name: 'bandera-sy', - keywords: ['Bandera'], + name: 'siria', + keywords: ['bandera', 'bandera-sy'], }, '🇸🇿': { - name: 'bandera-sz', - keywords: ['Bandera'], + name: 'swazilandia', + keywords: ['bandera', 'bandera-sz'], }, '🇹🇦': { - name: 'bandera-ta', - keywords: ['Bandera'], + name: 'tristán_de_acuña', + keywords: ['bandera', 'bandera-ta'], }, '🇹🇨': { - name: 'bandera-tc', - keywords: ['Bandera'], + name: 'islas_turcas_y_caicos', + keywords: ['bandera', 'bandera-tc'], }, '🇹🇩': { - name: 'bandera-td', - keywords: ['Bandera'], + name: 'chad', + keywords: ['bandera', 'bandera-td'], }, '🇹🇫': { - name: 'bandera-tf', - keywords: ['Bandera'], + name: 'territorios_australes_y_antárticas_franceses', + keywords: ['bandera', 'bandera-tf'], }, '🇹🇬': { - name: 'bandera-tg', - keywords: ['Bandera'], + name: 'togo', + keywords: ['bandera', 'bandera-tg'], }, '🇹🇭': { - name: 'bandera-th', - keywords: ['Bandera'], + name: 'tailandia', + keywords: ['bandera', 'bandera-th'], }, '🇹🇯': { - name: 'bandera-tj', - keywords: ['Bandera'], + name: 'tayikistán', + keywords: ['bandera', 'bandera-tj'], }, '🇹🇰': { - name: 'bandera-tk', - keywords: ['Bandera'], + name: 'tokelau', + keywords: ['bandera', 'bandera-tk'], }, '🇹🇱': { - name: 'bandera-tl', - keywords: ['Bandera'], + name: 'timor_oriental', + keywords: ['bandera', 'bandera-tl'], }, '🇹🇲': { - name: 'bandera-tm', - keywords: ['Bandera'], + name: 'turkmenistán', + keywords: ['bandera', 'bandera-tm'], }, '🇹🇳': { - name: 'bandera-tn', - keywords: ['Bandera'], + name: 'tunez', + keywords: ['bandera', 'bandera-tn'], }, '🇹🇴': { - name: 'bandera-to', - keywords: ['Bandera'], + name: 'tonga', + keywords: ['bandera', 'bandera-to'], }, '🇹🇷': { - name: 'bandera-tr', - keywords: ['Bandera'], + name: 'turquía', + keywords: ['bandera', 'bandera-tr'], }, '🇹🇹': { - name: 'bandera-tt', - keywords: ['Bandera'], + name: 'trinidad_y_tobago', + keywords: ['bandera', 'bandera-tt'], }, '🇹🇻': { - name: 'bandera-tv', - keywords: ['Bandera'], + name: 'tuvalu', + keywords: ['bandera', 'bandera-tv'], }, '🇹🇼': { - name: 'bandera-tw', - keywords: ['Bandera'], + name: 'taiwán', + keywords: ['bandera', 'bandera-tw'], }, '🇹🇿': { - name: 'bandera-tz', - keywords: ['Bandera'], + name: 'tanzania', + keywords: ['bandera', 'bandera-tz'], }, '🇺🇦': { - name: 'bandera-ua', - keywords: ['Bandera'], + name: 'ucrania', + keywords: ['bandera', 'bandera-ua'], }, '🇺🇬': { - name: 'bandera-ug', - keywords: ['Bandera'], + name: 'uganda', + keywords: ['bandera', 'bandera-ug'], }, '🇺🇲': { - name: 'bandera-um', - keywords: ['Bandera'], + name: 'islas_ultramarinas_menores_de_estados_unidos', + keywords: ['bandera', 'bandera-um'], }, '🇺🇳': { name: 'bandera-onu', - keywords: ['Bandera'], + keywords: ['Bandera', 'bandera-onu'], }, '🇺🇸': { - name: 'us', - keywords: ['Bandera'], + name: 'estados_unidos_de_américa', + keywords: ['bandera', 'bandera-us'], }, '🇺🇾': { - name: 'bandera-uy', - keywords: ['Bandera'], + name: 'uruguay', + keywords: ['bandera', 'bandera-uy'], }, '🇺🇿': { - name: 'bandera-uz', - keywords: ['Bandera'], + name: 'uzbekistan', + keywords: ['bandera', 'bandera-uz'], }, '🇻🇦': { - name: 'bandera-va', - keywords: ['Bandera'], + name: 'ciudad_del_vaticano', + keywords: ['bandera', 'bandera-va'], }, '🇻🇨': { - name: 'bandera-vc', - keywords: ['Bandera'], + name: 'san_vicente_y_las_granadinas', + keywords: ['bandera', 'bandera-vc'], }, '🇻🇪': { - name: 'bandera-ve', - keywords: ['Bandera'], + name: 'venezuela', + keywords: ['bandera', 'bandera-ve'], }, '🇻🇬': { - name: 'bandera-vg', - keywords: ['Bandera'], + name: 'islas_vírgenes_británicas', + keywords: ['bandera', 'bandera-vg'], }, '🇻🇮': { - name: 'bandera-vi', - keywords: ['Bandera'], + name: 'islas_vírgenes_de_los_estados_unidos', + keywords: ['bandera', 'bandera-vi'], }, '🇻🇳': { - name: 'bandera-vn', - keywords: ['Bandera'], + name: 'vietnam', + keywords: ['bandera', 'bandera-vn'], }, '🇻🇺': { - name: 'bandera-vu', - keywords: ['Bandera'], + name: 'vanuatu', + keywords: ['bandera', 'bandera-vu'], }, '🇼🇫': { - name: 'bandera-wf', - keywords: ['Bandera'], + name: 'wallis_y_futuna', + keywords: ['bandera', 'bandera-wf'], }, '🇼🇸': { - name: 'bandera-ws', - keywords: ['Bandera'], + name: 'samoa', + keywords: ['bandera', 'bandera-ws'], }, '🇽🇰': { - name: 'bandera-xk', - keywords: ['Bandera'], + name: 'kosovo', + keywords: ['bandera', 'bandera-xk'], }, '🇾🇪': { - name: 'bandera-ye', - keywords: ['Bandera'], + name: 'yemen', + keywords: ['bandera', 'bandera-ye'], }, '🇾🇹': { - name: 'bandera-yt', - keywords: ['Bandera'], + name: 'mayotte', + keywords: ['bandera', 'bandera-yt'], }, '🇿🇦': { - name: 'bandera-za', - keywords: ['Bandera'], + name: 'sudáfrica', + keywords: ['bandera', 'bandera-za'], }, '🇿🇲': { - name: 'bandera-zm', - keywords: ['Bandera'], + name: 'zambia', + keywords: ['bandera', 'bandera-zm'], }, '🇿🇼': { - name: 'bandera-zw', - keywords: ['Bandera'], + name: 'zimbabue', + keywords: ['bandera', 'bandera-zw'], }, '🏴󠁧󠁢󠁥󠁮󠁧󠁿': { - name: 'bandera-inglaterra', - keywords: ['Bandera'], + name: 'inglaterra', + keywords: ['bandera', 'bandera-inglaterra'], }, '🏴󠁧󠁢󠁳󠁣󠁴󠁿': { - name: 'bandera-escocia', - keywords: ['Bandera'], + name: 'escocia', + keywords: ['bandera', 'bandera-escocia'], }, '🏴󠁧󠁢󠁷󠁬󠁳󠁿': { - name: 'bandera-gales', - keywords: ['Bandera'], + name: 'gales', + keywords: ['bandera', 'bandera-gales'], }, }; diff --git a/assets/images/MCCGroupIcons/MCC-Airlines.svg b/assets/images/MCCGroupIcons/MCC-Airlines.svg new file mode 100644 index 000000000000..9d7924cff407 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Airlines.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Commuter.svg b/assets/images/MCCGroupIcons/MCC-Commuter.svg new file mode 100644 index 000000000000..2996c9f5f793 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Commuter.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Gas.svg b/assets/images/MCCGroupIcons/MCC-Gas.svg new file mode 100644 index 000000000000..519882921fb6 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Gas.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Goods.svg b/assets/images/MCCGroupIcons/MCC-Goods.svg new file mode 100644 index 000000000000..2aa86250e9d8 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Goods.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Groceries.svg b/assets/images/MCCGroupIcons/MCC-Groceries.svg new file mode 100644 index 000000000000..e957d6ee0238 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Groceries.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Hotel.svg b/assets/images/MCCGroupIcons/MCC-Hotel.svg new file mode 100644 index 000000000000..8de897bfafff --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Hotel.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Mail.svg b/assets/images/MCCGroupIcons/MCC-Mail.svg new file mode 100644 index 000000000000..56b4d7bd1005 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Mail.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/MCCGroupIcons/MCC-Meals.svg b/assets/images/MCCGroupIcons/MCC-Meals.svg new file mode 100644 index 000000000000..e8b9eab9d803 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Meals.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Misc.svg b/assets/images/MCCGroupIcons/MCC-Misc.svg new file mode 100644 index 000000000000..8bd292d0568f --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Misc.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-RentalCar.svg b/assets/images/MCCGroupIcons/MCC-RentalCar.svg new file mode 100644 index 000000000000..f88d28723569 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-RentalCar.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Services.svg b/assets/images/MCCGroupIcons/MCC-Services.svg new file mode 100644 index 000000000000..f4d632e86581 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Services.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Taxi.svg b/assets/images/MCCGroupIcons/MCC-Taxi.svg new file mode 100644 index 000000000000..89d3eb239371 --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Taxi.svg @@ -0,0 +1,3 @@ + + + diff --git a/assets/images/MCCGroupIcons/MCC-Utilities.svg b/assets/images/MCCGroupIcons/MCC-Utilities.svg new file mode 100644 index 000000000000..464344b41b4e --- /dev/null +++ b/assets/images/MCCGroupIcons/MCC-Utilities.svg @@ -0,0 +1,4 @@ + + + + diff --git a/assets/images/eReceipt-BGImage.svg b/assets/images/eReceipt-BGImage.svg new file mode 100644 index 000000000000..48aa548ad6ee --- /dev/null +++ b/assets/images/eReceipt-BGImage.svg @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/images/eReceiptIcon.svg b/assets/images/eReceiptIcon.svg new file mode 100644 index 000000000000..f4fc8c9fcc34 --- /dev/null +++ b/assets/images/eReceiptIcon.svg @@ -0,0 +1,3 @@ + + + diff --git a/contributingGuides/REVIEWER_CHECKLIST.md b/contributingGuides/REVIEWER_CHECKLIST.md index 6a5dffc8b073..d52d80a818bb 100644 --- a/contributingGuides/REVIEWER_CHECKLIST.md +++ b/contributingGuides/REVIEWER_CHECKLIST.md @@ -10,12 +10,12 @@ - [ ] I checked that screenshots or videos are included for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms) - [ ] I included screenshots or videos for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms) - [ ] I verified tests pass on **all platforms** & I tested again on: - - [ ] Android / native - - [ ] Android / Chrome - - [ ] iOS / native - - [ ] iOS / Safari - - [ ] MacOS / Chrome / Safari - - [ ] MacOS / Desktop + - [ ] Android: Native + - [ ] Android: mWeb Chrome + - [ ] iOS: Native + - [ ] iOS: mWeb Safari + - [ ] MacOS: Chrome / Safari + - [ ] MacOS: Desktop - [ ] If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack - [ ] I verified proper code patterns were followed (see [Reviewing the code](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md#reviewing-the-code)) - [ ] I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. `toggleReport` and not `onIconClick`). diff --git a/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Add-a-Deposit-Account-(AUD).md b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Add-a-Deposit-Account-(AUD).md new file mode 100644 index 000000000000..7273e5ece879 --- /dev/null +++ b/docs/articles/expensify-classic/bank-accounts-and-credit-cards/business-bank-accounts/Add-a-Deposit-Account-(AUD).md @@ -0,0 +1,22 @@ +--- +title: Add a Deposit Account (AUD) +description: Expensify allows you to add a personal bank account to receive reimbursements for your expenses. We never take money out of this account — it is only a place for us to deposit funds from your employer. This article covers deposit accounts for Australian banks. +--- + +## How-to add your Australian personal deposit account information +1. Confirm with your Policy Admin that they’ve set up Global Reimbursment +2. Set your default policy (by selecting the correct policy after clicking on your profile picture) before adding your deposit account. +3. Go to *Settings > Account > Payments* and click *Add Deposit-Only Bank Account* +![Click the Add Deposit-Only Bank Account button](https://help.expensify.com/assets/images/add-australian-deposit-only-account.png){:width="100%"} + +4. Enter your BSB, account number and name. If your screen looks different than the image below, that means your company hasn't enabled reimbursements through Expensify. Please contact your administrator and ask them to enable reimbursements. + +![Fill in the required fields](https://help.expensify.com/assets/images/add-australian-deposit-only-account-modal.png){:width="100%"} + +# How-to delete a bank account +Bank accounts are easy to delete! Simply click the red “Delete” button in the bank account under *Settings > Account > Payments*. + +![Click the Delete button](https://help.expensify.com/assets/images/delete-australian-bank-account.png){:width="100%"} + +You can complete this process on a computer or on the mobile app. + diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md b/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md index c4948b5b3083..33fbec003a91 100644 --- a/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md +++ b/docs/articles/expensify-classic/billing-and-subscriptions/Tax-Exempt.md @@ -1,5 +1,20 @@ --- title: Tax Exempt -description: Tax Exempt +description: Tax-exempt status in Expensify for organizations recognized by the IRS or local tax authorities. --- -## Resource Coming Soon! +# Overview +If your organization is recognized by the IRS or other local tax authorities as tax-exempt, that means you don’t need to pay any tax on your Expensify monthly bill. Please follow these instructions to request tax-exempt status. +# How to request tax-exempt status in Expensify +1. Go to **Settings > Account > Payments**. +1. Click on the option that says **Request Tax-Exempt Status**. +1. After you've requested tax-exempt status, Concierge (our support service) will start a conversation with you. They will ask you to upload a PDF of your tax-exempt documentation. This document should include your VAT number (or "RUT" in Chile). You can use one of the following documents: 501(c), ST-119, or a foreign tax-exempt declaration. +1. Our team will review your document and let you know if we need any more information. +1. Once everything is verified, we'll update your account accordingly. + +Once your account is marked as tax-exempt, the corresponding state tax will no longer be applied to future billing. + +If you need to remove your tax-exempt status, let your Account Manager know or contact Concierge. + +# FAQ +## What happens to my past Expensify bills that incorrectly had tax added to them? +Expensify can provide a refund for the tax you were charged on your previous bills. Please let your Account Manager know or contact Concierge if this is the case. diff --git a/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md b/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md index a5b0b26b2610..ae367d25891e 100644 --- a/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md +++ b/docs/articles/expensify-classic/expense-and-report-features/Attendee-Tracking.md @@ -1,5 +1,49 @@ --- title: Attendee Tracking -description: Attendee Tracking +description: Attendee Tracking is an easy way to record meeting and event attendees, as well as showing the amount per employee for transparent group spending. --- -## Resource Coming Soon! + +Attendee Tracking is an easy way to record meeting and event attendees, as well as showing the amount per employee for transparent group spending. + +## How to use Attendee Tracking +Every expense has an Attendees field and will list the expense creator’s name as the default attendee. The default set of attendees is a list of users from your workspaces and domain. You can add custom attendees by entering their names or email addresses into the Attendees field. + +## How to Add Additional Attendees to an Expense +* Go to the attendees field +* Search for the names of the attendees + * The default list will be of internal attendees belonging to your workspace and domain. + * External attendees are not part of your workspace or domain, so you will need to enter their name or email +* Select the attendees you would like to add +* Save the expense +* Once added, the list of attendees for each expense will be visible on the expense line. +* An amount per employee expense will also be displayed on the report for easy viewing + +# FAQ + +## Can I turn off attendee tracking? +Attendee tracking is a standard field on all expenses and cannot be turned off. + +## Can I remove attendees from the dropdown list? +It is not possible to remove attendees from the list once they have been added. + +## Can I remove myself as an attendee from an expense in my account? +Yes, but you will need to have at least one other attendee selected before you can remove yourself from the expense. + +## How can I see the cost breakdown by an attendee for an expense? +If you hover over the expense amount on your Expenses page you will be able to see this figure. This is also displayed on the report level in each expense line, under the total. + +## How is the cost breakdown calculated and can I adjust it? +The cost breakdown is an even split by however many attendees are listed on the report. It is not possible to edit this. + +## How do expense limits work and attendee tracking work? +Expense limits and workspace rules are applied individually per person. If an expense exceeds the limit for any attendee, a violation is triggered for that expense. + +## Will the expense be visible on the other attendees’ Expenses page? +No, the expense will only be shown in the expense creator’s account. + +## Is there a limit on how many attendees I can add to an expense? +There is no limit. + +## How can I remove attendees from an expense? +You can add or remove attendees from an expense as long as they are on a Draft report. Expenses on submitted reports cannot be edited, so you cannot remove attendees from these. + diff --git a/docs/articles/expensify-classic/getting-started/Plan-Types.md b/docs/articles/expensify-classic/getting-started/Plan-Types.md index f0323947ee12..90c632ffa5cc 100644 --- a/docs/articles/expensify-classic/getting-started/Plan-Types.md +++ b/docs/articles/expensify-classic/getting-started/Plan-Types.md @@ -1,5 +1,32 @@ --- -title: Plan-Types -description: Plan-Types +title: Plan Types +description: Learn which Expensify plan is the best fit for you --- -## Resource Coming Soon! +# Overview +You can access comprehensive information about Expensify's plans and pricing by visiting www.expensify.com/pricing. Below, we provide an overview of each plan type to assist you in selecting the one that best suits your business or personal requirements. + +## Free Plan +The Free plan is suited for small businesses, offering a dedicated workspace for efficiently handling Expensify card management, expense reimbursement, invoicing, and bill payment. This plan includes unlimited receipt scanning for all users within the company and the potential to earn up to 1% cashback on card spending exceeding $25,000 per month (across all cards). + +## Collect Workspace Plan +The Collect Workspace Plan is designed with small companies in mind, providing essential features like a single layer of expense approvals, reimbursement capabilities, corporate card management, and basic integration options such as QuickBooks Online, QuickBooks Desktop, and Xero. This plan is ideal for those who require simple expense management functions. + +## Control Workspace Plan +Our most popular option, the Control Workspace plan, offers a heightened level of control and Workspace customization. With a Control Workspace, you gain access to multi-level approval workflows, comprehensive corporate card management, advanced accounting integration, tax tracking capabilities, and advanced expense rules that facilitate the enforcement of your internal expense policy. This plan provides a robust set of features for effective expense management. + +## Individual Track Plan +The Track plan is tailored for solo Expensify users who don't require expense submission to others. Individuals or sole proprietors can choose the Track plan to customize their Individual Workspace to align with their personal expense tracking requirements. + +## Individual Submit Plan +The Submit plan is designed for individuals who need to keep track of their expenses and share them with someone else, such as their boss, accountant, or even a housemate. It's specifically tailored for single users who want to both track and submit their expenses efficiently. + +# FAQ + +## How can I change Individual plans? +You have the flexibility to switch between a Track and Submit plan, or vice versa, at any time by navigating to **Settings > Workspaces > Individual > *Workspace Name* > Plan**. This allows you to adapt your expense management approach as needed. + +## How can I upgrade Group plans? +You can easily upgrade from a Collect to a Control plan at any time by going to **Settings > Workspaces > Group > *Workspace Name* > Plan**. However, it's important to note that if you have an active Annual Subscription, downgrading from Control to Collect is not possible until your current commitment period expires. + +## How does pricing work if I have two types of Group Workspace plans? +If you have a Control and Collect Workspace, you will be charged at the Control Workspace rate. diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md index 3ee1c8656b4b..d8c7c145a670 100644 --- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md +++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md @@ -1,5 +1,144 @@ --- -title: Coming Soon -description: Coming Soon +title: QuickBooks Desktop +description: How to connect Expensify to QuickBooks Desktop and troubleshoot issues. --- -## Resource Coming Soon! +# Overview +QuickBooks Desktop is an accounting package developed by Intuit. It is designed for small and medium-sized businesses to help them manage their financial and accounting tasks. You can connect Expensify to QuickBooks Desktop to make expense management seamless. +To connect Expensify with QuickBooks Desktop, using Right Networks as your hosting platform is best. Right Networks is a cloud-based service we recommend for this integration. If you need a Right Networks account, complete [this form](https://info.rightnetworks.com/partner-expensify) and contact a Sales Consultant to start the process. + +# How to connect to QuickBooks Desktop +Before you link your Expensify policy with QuickBooks Desktop, ensure you log in as an Admin in QuickBooks. Also, check that the company file you want to connect to is the only one open. + +## Set up submitters in QuickBooks Desktop +For a seamless integration, here are the steps to follow: +* Make sure all report submitters are set up as Vendors in QuickBooks Desktop and their Expensify email is in the "Main Email" field of their Vendor record. You can do this in the vendor section of QuickBooks. +* If you want to export reports to your users' employee records instead of vendor records, select Check or Journal Entry as your reimbursable export option. +* To set up Expensify users as employees, activate QuickBooks Desktop Payroll. This module is necessary to access the Employee Profile tab, where you can enter the submitter's email addresses. + +## Enable/install the Expensify Sync Manager +Navigate to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections**, select the Connect to QuickBooks Desktop radio button and click Connect to QuickBooks. + +**Enable the Expensify Sync Manager in Right Networks (recommended)** +*Please note: Single-user mode in QuickBooks Desktop is required.* +If you don't yet have an account with Right Networks, you must first contact Right Networks [here](https://info.rightnetworks.com/partner-expensify). You can enable the Expensify Sync Manager yourself from your Right Networks portal's **My Account** section or contact Right Networks for assistance. + +**OR, install the Expensify Sync Manager on Your Third-Party Remote Desktop.** +To download the Sync Manager to your desktop, you must contact your third-party remote desktop provider and request permission. They might have security restrictions, so it's best to communicate with them directly to avoid potential problems with the Sync Manager. Remember that the Sync Manager program file should be stored in the same location (i.e., the same drive) as your QuickBooks Desktop program. + +## Complete the connection +1. Open QuickBooks and access your desired Company File using the QuickBooks Admin credentials. Admin credentials are necessary for creating the connection due to permission requirements, but you won't need to stay logged in as an admin for syncing or exporting. +2. Navigate to your Expensify policy settings by going to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections**. Copy the Token by selecting the copy icon. +3. While QuickBooks is still running, launch the Expensify Sync Manager. Paste your Token into the Sync Manager and click **Save**. +4. Once the Sync Manager status displays **Connected**, return to Expensify and click the *Continue* button. + +## Allow access +1. Return to QuickBooks, and you'll encounter an **Application Certificate** screen. On the first page of the Certificate screen, click **Yes, always; allow access even if QuickBooks is not running** and then click **Continue**. +2. On the second page of the Certificate screen, choose the Admin user from the dropdown menu, and then click *Done* to complete this step. Note that selecting Admin here does not require you to be logged in as an admin to use this connection; it's simply selecting the appropriate permissions. +3. Head back to Expensify and patiently wait for the sync process to finish, then move on to the configuration. + +# How to configure export settings for QuickBooks Desktop +To Configure Settings, go to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** and click **Configure**. + +## Preferred Exporter +This person is used in QuickBooks Desktop as the export user. They will also receive notifications for errors. + +## Date +Choose either the report's submitted date, the report's exported date, or the date of the last expense on the report when exporting reports to QuickBooks Desktop. + +## Use unique reference numbers +Enable this to allow use of a unique reference number for each transaction. Disable this to use the same Report ID for all expenses from a certain report. + +## Reimbursable expenses +* **Vendor Bill (recommended):** A single itemized vendor bill for each Expensify report. An A/P account is required to export to a vendor bill. +* **Check:** A single itemized check for each Expensify report. +* **Journal Entry:** A single itemized journal entry for each Expensify report. + +## Non-reimbursable expenses +**Credit Card Expenses:** +* Each expense will appear as a separate credit card transaction. +* The posting date will match your credit card statement. +* To display the merchant name in the payee field in QuickBooks Desktop, ensure that a matching Vendor exists in QuickBooks. Expensify searches for an exact match during export. If no match is found, the payee is mapped to a **Credit Card Misc.** Vendor created by Expensify. +* If you're centrally managing company cards through Domain Control, you can export expenses from each card to a specific QuickBooks account (detailed instructions available). + +**Debit Card Expenses:** +* Expenses export as individual itemized checks for each Expensify report. +* The check is written to the "vendor," which is the person who created or submitted the report in Expensify. + +**Vendor Bill:** +* Each Expensify report results in a single itemized vendor bill. +* The bill is associated with the "vendor," which is the individual responsible for creating or submitting the report in Expensify. + +# How to configure coding for QuickBooks Desktop +## Categories +Expensify's integration with QuickBooks brings in your Chart of Accounts as Categories in Expensify automatically. Here's how to manage them: +1. After connecting, go to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Categories** to view the accounts imported from QuickBooks Desktop. +2. You can use the enable/disable button to choose which Categories your employees can access. Additionally, you can set specific rules for each Category via the blue settings cog. +3. Expensify offers Auto-Categorization to automatically assign expenses to the appropriate expense categories. +4. If needed, you can edit the names of the imported Categories to simplify expense coding for your employees. Keep in mind that if you make changes to these accounts in QuickBooks Desktop, the category names in Expensify will update to match them during the next sync. +5. _**Important:**_ Each expense must have a category selected to export to QuickBooks Desktop. The selected category must be one imported from QuickBooks Desktop; you cannot manually create categories within Expensify policy settings. +## Classes +Classes can be imported from QuickBooks as either tags (line-item level) or report fields (header level). + +## Customers/Projects +You can bring in Customers/Projects from QuickBooks into Expensify in two ways: as tags (at the line-item level) or as report fields (at the header level). If you're utilizing Billable Expenses in Expensify, here's what you need to know: +* Customers/Projects must be enabled if you're using Billable Expenses. +* Expenses marked as "Billable" need to be tagged with a Customer/Project to successfully export them to QuickBooks. + +## Items +Items can be imported from QuickBooks as categories alongside your expense accounts. + +# FAQ +## How do I sync my connection? +1: Ensure that both the Expensify Sync Manager and QuickBooks Desktop are running. +2: On the Expensify website, navigate to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** > **QuickBooks Desktop**, and click **Sync now**. +3: Wait for the syncing process to finish. Typically, this takes about 2-5 minutes, but it might take longer, depending on when you last synced and the size of your QuickBooks company file. The page will refresh automatically once syncing is complete. + +We recommend syncing at least once a week or whenever you make changes in QuickBooks Desktop that could impact how your reports export from Expensify. Changes could include adjustments to your Chart of Accounts, Vendors, Employees, Customers/Jobs, or Items. Remember, both the Sync Manager and QuickBooks Desktop need to be running for syncing or exporting to work. + +## Can I export negative expenses? +Generally, you can export negative expenses to QuickBooks Desktop successfully, regardless of your option. However, please keep in mind that if you have *Check* selected as your export option, the report's total cannot be negative. + +## How does multi-currency work with QuickBooks Desktop? +When using QuickBooks Desktop Multi-Currency, there are some limitations to consider based on your export options: +1. **Vendor Bills and Checks:** The currency of the vendor and the currency of the account must match, but they do not have to be in the home currency. +2. **Credit Card:** If an expense doesn't match an existing vendor in QuickBooks, it exports to the **Credit Card Misc.** vendor created by Expensify. When exporting a report in a currency other than your home currency, the transaction will be created under the vendor's currency with a 1:1 conversion. For example, a transaction in Expensify for $50 CAD will appear in QuickBooks as $50 USD. +3. **Journal Entries:** Multi-currency exports will fail because the account currency must match both the vendor currency and the home currency. + +# Sync and export errors +## Error: No Vendor Found For Email in QuickBooks +To address this issue, ensure that each submitter's email is saved as the **Main Email** in their Vendor record within QuickBooks Desktop. Here's how to resolve it: +1. Go to your Vendor section in QuickBooks. +2. Verify that the email mentioned in the error matches the **Main Email** field in the respective vendor's record. It's important to note that this comparison is case-sensitive, so ensure that capitalization matches as well. +3. If you prefer to export reports to your users' employee records instead of their vendor records, select either **Check** or **Journal Entry** as your reimbursable export option. If you are setting up Expensify users as employees, activate QuickBooks Desktop Payroll to access the Employee Profile tab where submitter email addresses need to be entered. +4. Once you've added the correct email to the vendor record, save this change, and then sync your policy before attempting to export the report again. + +## Error: Do Not Have Permission to Access Company Data File +To resolve this error, follow these steps: +1. Log into QuickBooks Desktop as an Admin in single-user mode. +2. Go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**. +3. Select the Expensify Sync Manager and click on **Properties**. +4. Ensure that **Allow this application to login automatically** is checked, and then click **OK**. Close all windows within QuickBooks. +5. If you still encounter the error after following the above steps, go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**, and remove the Expensify Sync Manager from the list. +6. Next, attempt to sync your policy again in Expensify. You'll be prompted to re-authorize the connection in QuickBooks. +7. Click **Yes, always; allow access even if QuickBooks is not running.** +8. From the dropdown, select the Admin user, and then click **Continue**. Note that selecting **Admin** here doesn't mean you always have to be logged in as an admin to use the connection; it's just required for setting up the connection. +9. Click **Done** on the pop-up window and return to Expensify, where your policy should complete the syncing process. + +## Error: The Wrong QuickBooks Company is Open. +This error suggests that the wrong company file is open in QuickBooks Desktop. To resolve this issue, follow these steps: +1. First, go through the general troubleshooting steps as outlined. +2. If you can confirm that the incorrect company file is open in QuickBooks, go to QuickBooks and select **File** > **Open or Restore Company** > _[Company Name]_ to open the correct company file. After doing this, try syncing your policy again. +3. If the correct company file is open, but you're still encountering the error, completely close QuickBooks Desktop, reopen the desired company file and then attempt to sync again. +4. If the error persists, log into QuickBooks as an admin in single-user mode. Then, go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences** and remove the Expensify Sync Manager from the list. +5. Next, try syncing your policy again in Expensify. You'll be prompted to re-authorize the connection in QuickBooks, allowing you to sync successfully. +6. If the error continues even after trying the steps above, double-check that the token you see in the Sync Manager matches the token in your connection settings. + +## Error: The Expensify Sync Manager Could Not Be Reached. +To resolve this error, follow these steps: +*Note: You must be in single-user mode to sync.* + +1. Ensure that both the Sync Manager and QuickBooks Desktop are running. +2. Confirm that the Sync Manager is installed in the correct location. It should be in the same location as your QuickBooks application. If QuickBooks is on your local desktop, the Sync Manager should be there, too. If QuickBooks is on a remote server, install the Sync Manager there. +Verify that the Sync Manager's status is **Connected**. +3. If the Sync Manager status is already **Connected**, click **Edit** and then *Save* to refresh the connection. Afterwards, try syncing your policy again. +4. If the error persists, double-check that the token you see in the Sync Manager matches the token in your connection settings. diff --git a/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md b/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md index 3ee1c8656b4b..f692f8f8d62e 100644 --- a/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md +++ b/docs/articles/expensify-classic/policy-and-domain-settings/Invoicing.md @@ -1,5 +1,64 @@ --- -title: Coming Soon -description: Coming Soon +title: Expensify Invoicing +description: Expensify Invoicing supports your business with unlimited invoice sending and receiving, payments, and status tracking in one single location. --- -## Resource Coming Soon! +# Overview +Expensify Invoicing lets you create and send invoices, receive payments, and track the status of your invoices with Expensify, regardless of whether your customer has an Expensify account. Invoicing is included with all Expensify subscriptions, no matter the plan — just pay the processing fee (2.9%) per transaction. + +# How to Set Up Expensify Invoicing + +**If you have a Group Workspace:** + +1. Log into your Expensify account from the web (not the mobile app) +3. Head to **Settings** > **Workspaces** > **Group** > [_Workspace Name_] > [**Invoices**](https://expensify.com/policy?param={"policyID":"20AB6A03EB9CE54D"}#invoices). + +**If you have an Individual Workspace:** + +1. Log into your Expensify account from the web (not the mobile app) +2. Head to **Settings** > **Workspaces** > **Individual** > [_Workspace Name_]> [**Invoices**](https://expensify.com/policy?param={"policyID":"BD5FB746D3B220D6"}#invoices). + +Here, you’ll be able to create a markup or add a payment account. Don’t forget you need a verified bank account to send or accept invoice payments via ACH. + +# Deep Dive + +To help your invoice stand out and look more professional, you can: + +- Add your logo +- Set your workspace currency to add default report-level fields +- Create additional report-level fields to display more details + +## Add a Logo + +From your Expensify account on the web (not the mobile app), go to **Settings** > **Account** > **Account Details**. Then click **Edit Photo** under _Your Details_ to upload your logo. + +## Set the Workspace Currency + +To set your currency, head to **Settings** > **Workspaces** > **Individual** or **Group** > **Reports**. This will add default report-level fields to your invoices. You can see these at the bottom of your [**Reports**](https://expensify.com/reports) page. + +Here are the default report-level fields based on common currencies: + +- GBP: VAT Number & Supplier Address (your company address) +- EUR: VAT Number & Supplier Address (your company address) +- AUD: ABN Number & Supplier Address (your company address) +- NZD: GST Number & Supplier Address (your company address) +- CAD: Business Number & Supplier Address (your company address) + +## Adding Additional Fields to Your Invoices + +In addition to the default report-level fields, you can create custom invoice fields. + +At the bottom of the same Reports page, under the _Add New Field_ section, you’ll have multiple options. + +- **Field Title**: This is the name of the field as displayed on your invoice. +- **Type**: You have the option to select a _text-based_ field, a _dropdown_ of selections, or a _date_ selector. +- **Report Type**: Select _Invoice_ to add the field to your invoices. + +Don’t forget to click the **Add** button once you’ve set your field parameters! + +For example, you may want to add a PO number, business address, website, or any other custom fields. + +_Please check the regulations in your local jurisdiction to ensure tax and business compliance._ + +## Removing Fields from Your Invoices + +If you want to delete a report field, click the red trashcan on the field in your **Workspace** > **Individual** or **Group** > **Report** settings to remove it from all future invoices. Unsent invoices will have a red **X** next to the report field, which you can click to remove before sending the invoice to your customer. diff --git a/docs/articles/new-expensify/integrations/accounting-integrations/Xero b/docs/articles/new-expensify/integrations/accounting-integrations/Xero new file mode 100644 index 000000000000..45aec32fb708 --- /dev/null +++ b/docs/articles/new-expensify/integrations/accounting-integrations/Xero @@ -0,0 +1,261 @@ +--- +title: The Xero Integration +description: Everything you need to know about Expensify's direct integration with Xero +--- + + +# About + +The integration enables seamless import of expense accounts into Expensify and sends expense reports back to Xero as purchasing bills awaiting payment or "spend money" bank transactions. + +# How-to Connect to Xero + +## Prerequisites + +You must be a Workspace Admin in Expensify using a Collect or Control Workspace to connect your Xero account to Expensify. + +## Connect Expensify and Xero + +1. Let's get started by heading over to your Settings. You can find it by following this path: *Settings > Workspaces > Groups > [Workspace Name] > Connections > Xero.* +2. To connect Expensify to Xero, click on the "Connect to Xero” button, then choose "Create a new Xero connection." +3. Next, enter your Xero login details. After that, you'll need to select the Xero organization you want to link with Expensify. Remember, you can connect one organization for each Workspace. + +One important note: Starting in September 2021, there's a chance for Cashbook and Ledger-type organizations in Xero. Apps like Expensify won't be able to create invoices and bills for these accounts using the Xero API. So, if you're using a Cashbook or Ledger Xero account, please be aware that this might affect your Expensify integration. + +# How to Configure Export Settings for Xero + +When you integrate Expensify with Xero you gain control over several settings that determine how your reports will be displayed in Xero. To manage these settings simply follow this path: *Settings > Workspaces > Group > [Workspace Name] > Connections > Accounting Integrations > Xero > Configure > Export*. This is where you can fine-tune how your reports appear on the Xero side, making your expense management a breeze! + +## Xero Organization + +When you have multiple organizations set up in Xero you can choose which one you'd like to connect. Here are some essential things to keep in mind: + +1. Organization Selection: You'll see this option only if you have multiple organizations configured in Xero. +2. One Workspace, One Organization: Each Workspace can connect to just one organization at a time. It's a one-to-one connection. +3. Adding New Organizations: If you create a new organization in Xero after your initial connection, you'll need to disconnect and then reconnect it to Xero. Don't forget to take a screenshot of your current settings by clicking on "Configure" and checking the Export, Coding, and Advanced tabs. This way, you can easily set everything up again. + +Now you can seamlessly manage your connections with Xero while staying in control of your configurations! + +## Preferred Exporter + +Any Workspace admin can export to Xero, but only the preferred exporter will see reports that are ready for export in their Home. + +## Reimbursable Expenses + +Export to Xero as bills awaiting payment with the following additional settings: + +- Bill date — the bill is posted on the last day of the month in which expenses were incurred. + +To view the bills in Xero, navigate to *Business > Purchase Overview > Awaiting Payments*. Bills will be payable to the individual who created and reported the expense. + +## Non-reimbursable Expenses + +When you export non-reimbursable expenses, like company card transactions, to Xero they'll show up as bank transactions. Each expense is neatly listed as a separate line item in the bank account of your choice. Plus the transaction date matches the date on your bank statement for seamless tracking. + +To check out these expenses in Xero please follow these steps: + +1. Head over to your Dashboard. +2. Select your company card. +3. Locate the specific expense you're interested in. + +If you're managing company cards centrally, you can export expenses from each card to a designated account in Xero using Domains. This way, you have complete control and clarity over your company's finances! + +# How to Configure Coding for Xero + +The Coding tab in Expensify is where you configure Xero information to ensure accurate expense coding by your employees. Here's how you can access these settings: + +1. Navigate to Settings. +2. Go to Workspace within your specified group (Workspace Name). +3. Click on Connections, and then hit the Configure button. +4. Now, select the Coding tab. + +## Categories + +Xero expense accounts and those marked "Show In Expense Claims" will be automatically imported into Expensify as Categories. + +To manage these categories, follow these steps: + +1. After connecting, go to *Settings > Workspaces > Groups > [Workspace Name] > Categories*. +2. You can enable/disable categories using the checkbox. +3. For specific category rules (like default tax rate, maximum amount, receipts required, comments, and comment hints), click the settings cog. +4. Note that each expense must have a category selected for it to export to Xero, and these categories need to be imported from Xero; manual creation isn't an option within Workspace settings. + +## Tracking Categories + +1. If you use Tracking categories in Xero, you can import them into Expensify as Tags, Report Fields, or the Xero contact default. +- Tags apply a tracking category per expense. +- Report Field applies a tracking category to the entire report. +- Xero contact default applies the default tracking category set for the submitter in Xero. + +## Tax + +Looking to track tax in Expensify? Make sure that you have tax rates enabled in Xero and we will automatically grab those rates from Xero to allow your employees to categorize expenses with the appropriate tax rate. As an admin, you have the ability to set a default rate and also hide rates that are not applicable to the Workspace members. + +Tax tracking allows you to apply a tax rate and tax amount to each expense. +1. To set this up, enable Tax tracking in your Xero configuration. +2. After connecting, go to *Settings > Workspaces > Groups > [Workspace Name] > Tax to manage imported taxes from Xero.* +3. You can enable/disable taxes and set default tax rates for both Workspace currency expenses and foreign currency expenses. + +## Billable Expenses + +If you bill expenses to your customers, you can track and invoice them using Expensify and Xero. + +1. When enabled, Xero customer contacts are imported into Expensify as Tags for expense tracking. +- Note: In Xero, a Contact isn't a 'Customer' until they've had a bill raised against them. If you don't see your Customer imported as a tag, try raising a dummy invoice in Xero and then deleting/voiding it. +2. After exporting to Xero, tagged billable expenses can be included on a sales invoice to your customer. + +Please ensure that you meet the following requirements for expenses to be placed on a sales invoice: +1. Billable Expenses must be enabled in the Xero configuration settings. +2. The expense must be marked as billable. +3. The expense must be tagged with a customer. + +These steps should help you seamlessly manage your Xero integration within Expensify. + +# How to Configure Xero’s Advanced Settings + +If you've already set up your integration, but want to make adjustments, simply follow these steps: + +1. Go to Settings. +2. Then, navigate to Workspaces within your designated group [Workspace Name]. +3. Click on Connections, and next, hit the Configure button. + +From there, you can dive into the "Advanced" tab to make any additional tweaks. + +## Auto Sync + +For non-reimbursable reports: Once a report has completed the approval workflow in Expensify, we'll automatically queue it for export to Xero. + +But, if you've added a business bank account for ACH reimbursement, any reimbursable expenses will be sent to Xero automatically when the report is marked as reimbursed or enabled for reimbursement. + +### Controlling Newly Imported Categories: + +You can decide how newly imported categories behave in Expensify: + +1. Enabling or disabling this control determines the status of new categories imported from Xero to Expensify. Enabled categories are visible for employees when they categorize expenses, while disabled categories remain hidden. + +These settings give you the flexibility to manage your expenses and Workspace in the way that best suits your needs! + +## Sync Reimbursed Reports + +This nifty setting lets you synchronize the status of your reports between Expensify and Xero. Utilizing this setting will make sure that there is no confusion or possibility that a reimbursable report is paid out twice by mistake or that a non-reimbursable report is double entered throwing off month-end reconciliation. Here's how it works: + +1. When you reimburse a report via ACH direct deposit within Expensify, the purchase bill will automatically be marked as paid in Xero, and Expensify will note it as reimbursed. +2. Don't forget to pick the Xero account where the corresponding bill payment should be recorded. +3. It's a simple way to keep everything in sync, especially when you're awaiting payment. + +# Deep Dive + +## An Automatic Export Fails + +Sometimes, reports may encounter issues during automatic export to Xero. Not to worry, though! Here's what happens: + +1. The Technical Contact, your go-to person for technical matters, will receive an email explaining the problem. +2. You'll also find specific error messages at the bottom of the report. +3. To get things back on track, the report will be placed in the preferred exporter’s Home. They can review it and resolve any issues. + +## Consider Enforcing Expense Workspace Workflows: + +For added control, you can adjust your Workspace settings to strictly enforce expense Workspace. This way, you guarantee that your Workspace’s workflow is always followed. By default this flow is in place, but employees can modify the person they submit their reports to if it's not strictly enforced. + +## Customize Purchase Bill Status (Optional): + +You have the flexibility to set the status of your purchase bills just the way you want. Choose from the following options: + +1. Draft: Keep bills in a draft state until you're ready to finalize them. +2. Awaiting Approval: If you need approval before processing bills, this option is here for you. + +## Multi-Currency + +### Handling Multi-Currency in Xero + +When dealing with multi-currency transactions in Xero and exporting reimbursable expenses from Expensify here's what you need to know: + +1. The bill created in Xero will adopt the output currency set in your Expensify Workspace, provided that it's enabled in Xero. +2. Your general ledger reports will automatically convert to your home currency in Xero, leveraging the currency exchange rates defined in your Xero settings. It ensures everything aligns seamlessly. + +Now, for non-reimbursable expenses, things work slightly differently: + +1. Bank transactions will use the currency specified in your bank account in Xero, regardless of the currency used in Expensify. +2. If these currencies don't match, no worries! We apply a 1:1 exchange rate to make things smooth. To ensure a hassle-free experience, just ensure that the output currency in Expensify matches the currency specified in your Xero bank account. + +## Tax + +### Enabling Tax Tracking for Seamless Integration: + +To simplify tax tracking, enable it in your Xero configuration. This action will automatically bring all your Xero tax settings into Expensify, turning them into usable Taxes. + +### After connecting your Xero account with Expensify: + +1. Head to Settings. +2. Navigate to Workspaces within your specific group [Workspace Name]. +3. Click on Tax to view the taxes that have been imported from Xero. + +Now, here's where you can take control: + +1. Use the enable/disable button to choose which taxes your employees can apply to their expenses. Customize it to fit your needs. +2. You can set a default tax rate for expenses in your Workspace currency. Additionally, if you deal with foreign currency expenses, you have the option to set another default tax (including exempt) that will automatically apply to all new expenses in foreign currencies. + +This setup streamlines your tax management, making it effortless for your team to handle taxes on their expenses. + +## Export Invoices to Xero + +You can effortlessly export your invoices from Expensify to Xero and even attribute them to the right Customer. Plus, when you mark an invoice as paid in Expensify, the same status will smoothly transfer to Xero and vice versa, keeping your invoice tracking hassle-free. Let's dive in: + +### Setting up Invoice Export to Xero: + +1. Navigate to Settings. +2. Go to Workspaces within your designated group [Workspace Name]. +3. Click on Connections, then select Configuration. +4. Now, click on the Advanced tab. + +### Selecting Your Xero Invoice Collection Account: + +1. Scroll down until you find "Xero invoice collection account." You'll see a dropdown list of your available Accounts Receivable accounts imported from Xero. +2. Simply choose the account where you'd like your invoices to be exported. + +Pro Tip: If you don't see any accounts in the dropdown, try syncing your Xero connection. To do this, go back to the Connections page and hit "Sync Now." + +### Exporting an Invoice to Xero: + +Invoices will automatically make their way to Xero when they're in the Processing or Paid state. This ensures consistent tracking of unpaid and paid invoices. However, if you have Auto Sync disabled, you'll need to manually export your invoices along with your expense reports. Here's how: + +1. Head to your Reports page. +2. Use the filters to locate the invoices you want to export. +3. Select the invoices you wish to export. +4. Click Export to > Xero on the top right-hand side. + +### Matching Customers and Emails: + +When exporting to Xero, we match the recipient's email address with a customer record in Xero. So, make sure each customer in Xero has their email listed in their profile. +If we can't find a match, we'll create a new customer record in Xero. + +### Updating Invoice Status: + +1. When you mark an invoice as Paid in Expensify, this status will automatically reflect in Xero. +2. Similarly, if you mark an invoice as Paid in Xero, it will update automatically in Expensify. +3. The payment will be recorded in the Collection account you've chosen in your Advanced Settings Configuration. + +And that's it! You've successfully set up and managed your invoice exports to Xero, making your tracking smooth and efficient. + +# FAQ + +## Will receipt images be exported to Xero? + +Yes! The receipt images will be exported to Xero. To see them in Xero click the 'paper' icon in the upper right corner of the expense details and view a PDF of the Expensify report including the receipt image. + +## How does Auto Sync work if your workspace was initially connected to Xero with Auto Sync disabled? + +You can safely switch it on without affecting existing reports that haven't been exported. + +## How does Auto Sync work if a report has already been exported to Xero and reimbursed through ACH or marked as reimbursed in Expensify? + +It will be automatically marked as paid in Xero during the next sync. You may either manually update by clicking Sync Now in the Connections tab or Expensify does this on your behalf overnight every day! + +## How does Auto Sync work if a report has been exported to Xero and marked as paid in Xero? + +It will be automatically marked as reimbursed in Expensify during the next sync. If you need it updated immediately please go to the Connections tab and click Sync Now or if you can wait just let Expensify do it for you overnight. + +## How does Auto Sync work if a report has been exported to Xero and marked as paid in Xero? + +Reports that haven't been exported to Xero won't be sent automatically. +--> diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist index 9082f991bf75..7d77ddebb8fa 100644 --- a/ios/NewExpensify/Info.plist +++ b/ios/NewExpensify/Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.3.79 + 1.3.80 CFBundleSignature ???? CFBundleURLTypes @@ -40,7 +40,7 @@ CFBundleVersion - 1.3.79.3 + 1.3.80.0 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist index 614979cf57b7..75730cafe16c 100644 --- a/ios/NewExpensifyTests/Info.plist +++ b/ios/NewExpensifyTests/Info.plist @@ -15,10 +15,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.3.79 + 1.3.80 CFBundleSignature ???? CFBundleVersion - 1.3.79.3 + 1.3.80.0 diff --git a/package-lock.json b/package-lock.json index ddebbe8a3832..2b3fb83b999f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "new.expensify", - "version": "1.3.79-3", + "version": "1.3.80-0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "new.expensify", - "version": "1.3.79-3", + "version": "1.3.80-0", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -51,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#f76ff4badf0934e21ac6c3f195ebc5791bb72247", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b", "fbjs": "^3.0.2", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", @@ -30218,8 +30218,8 @@ }, "node_modules/expensify-common": { "version": "1.0.0", - "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247", - "integrity": "sha512-RCC3VBRIoW1ZF+wZktHT+0ht6EUjNfCKW4g44RR5570dRpN9SrJASGt2OnEbz6mrbohWRgAaKmB4+nfiQX5ndQ==", + "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b", + "integrity": "sha512-mD9p6Qj8FfvLdb6JLXvF0UNqLN6ymssUU67Fm37zmK18hd1Abw+vR/pQkNpHR2iv+KRs8HdcyuZ0vaOec4VrFQ==", "license": "MIT", "dependencies": { "classnames": "2.3.1", @@ -74887,9 +74887,9 @@ } }, "expensify-common": { - "version": "git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247", - "integrity": "sha512-RCC3VBRIoW1ZF+wZktHT+0ht6EUjNfCKW4g44RR5570dRpN9SrJASGt2OnEbz6mrbohWRgAaKmB4+nfiQX5ndQ==", - "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247", + "version": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b", + "integrity": "sha512-mD9p6Qj8FfvLdb6JLXvF0UNqLN6ymssUU67Fm37zmK18hd1Abw+vR/pQkNpHR2iv+KRs8HdcyuZ0vaOec4VrFQ==", + "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b", "requires": { "classnames": "2.3.1", "clipboard": "2.0.4", diff --git a/package.json b/package.json index 9a3b9ed3af86..80320df08d69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "new.expensify", - "version": "1.3.79-3", + "version": "1.3.80-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.", @@ -94,7 +94,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#f76ff4badf0934e21ac6c3f195ebc5791bb72247", + "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b", "fbjs": "^3.0.2", "htmlparser2": "^7.2.0", "idb-keyval": "^6.2.1", diff --git a/src/App.js b/src/App.js index 1d2e07345c24..27e8105c2189 100644 --- a/src/App.js +++ b/src/App.js @@ -26,6 +26,7 @@ import {ReportAttachmentsProvider} from './pages/home/report/ReportAttachmentsCo import * as Session from './libs/actions/Session'; import useDefaultDragAndDrop from './hooks/useDefaultDragAndDrop'; import OnyxUpdateManager from './libs/actions/OnyxUpdateManager'; +import {SidebarNavigationContextProvider} from './pages/home/sidebar/SidebarNavigationContext'; // 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()) { @@ -64,6 +65,7 @@ function App() { EnvironmentProvider, ThemeProvider, ThemeStylesProvider, + SidebarNavigationContextProvider, ]} > diff --git a/src/CONST.ts b/src/CONST.ts index 9f16d7f9ccab..23957827d140 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -134,6 +134,8 @@ const CONST = { SQL_DATE_TIME: 'YYYY-MM-DD HH:mm:ss', FNS_FORMAT_STRING: 'yyyy-MM-dd', LOCAL_TIME_FORMAT: 'h:mm a', + YEAR_MONTH_FORMAT: 'yyyyMM', + MONTH_FORMAT: 'MMMM', WEEKDAY_TIME_FORMAT: 'eeee', MONTH_DAY_ABBR_FORMAT: 'MMM d', SHORT_DATE_FORMAT: 'MM-dd', @@ -476,20 +478,21 @@ const CONST = { ACTIONS: { LIMIT: 50, TYPE: { - APPROVED: 'APPROVED', ADDCOMMENT: 'ADDCOMMENT', + APPROVED: 'APPROVED', + CHRONOSOOOLIST: 'CHRONOSOOOLIST', CLOSED: 'CLOSED', CREATED: 'CREATED', - TASKEDITED: 'TASKEDITED', - TASKCANCELLED: 'TASKCANCELLED', IOU: 'IOU', MODIFIEDEXPENSE: 'MODIFIEDEXPENSE', REIMBURSEMENTQUEUED: 'REIMBURSEMENTQUEUED', RENAMED: 'RENAMED', - CHRONOSOOOLIST: 'CHRONOSOOOLIST', + REPORTPREVIEW: 'REPORTPREVIEW', + SUBMITTED: 'SUBMITTED', + TASKCANCELLED: 'TASKCANCELLED', TASKCOMPLETED: 'TASKCOMPLETED', + TASKEDITED: 'TASKEDITED', TASKREOPENED: 'TASKREOPENED', - REPORTPREVIEW: 'REPORTPREVIEW', POLICYCHANGELOG: { ADD_APPROVER_RULE: 'POLICYCHANGELOG_ADD_APPROVER_RULE', ADD_CATEGORY: 'POLICYCHANGELOG_ADD_CATEGORY', @@ -688,6 +691,7 @@ const CONST = { }, }, MCC_GROUPS: { + AIRLINES: 'Airlines', COMMUTER: 'Commuter', GAS: 'Gas', GOODS: 'Goods', @@ -927,6 +931,7 @@ const CONST = { RECEIPTS: 'receipts@expensify.com', STUDENT_AMBASSADOR: 'studentambassadors@expensify.com', SVFG: 'svfg@expensify.com', + EXPENSIFY_EMAIL_DOMAIN: '@expensify.com', }, ACCOUNT_ID: { @@ -1167,6 +1172,14 @@ const CONST = { AUDITOR: 'auditor', USER: 'user', }, + AUTO_REPORTING_FREQUENCIES: { + IMMEDIATE: 'immediate', + WEEKLY: 'weekly', + SEMI_MONTHLY: 'semimonthly', + MONTHLY: 'monthly', + TRIP: 'trip', + MANUAL: 'manual', + }, ROOM_PREFIX: '#', CUSTOM_UNIT_RATE_BASE_OFFSET: 100, OWNER_EMAIL_FAKE: '_FAKE_', @@ -1219,6 +1232,13 @@ const CONST = { INDIVIDUAL: 'individal', NONE: 'none', }, + STATE: { + OPEN: 3, + NOT_ACTIVATED: 4, + STATE_DEACTIVATED: 5, + CLOSED: 6, + STATE_SUSPENDED: 7, + }, }, AVATAR_ROW_SIZE: { DEFAULT: 4, @@ -2692,19 +2712,31 @@ const CONST = { DEFAULT_COORDINATE: [-122.4021, 37.7911], STYLE_URL: 'mapbox://styles/expensify/cllcoiqds00cs01r80kp34tmq', }, + ONYX_UPDATE_TYPES: { HTTPS: 'https', PUSHER: 'pusher', }, + EVENTS: { SCROLLING: 'scrolling', }, + HORIZONTAL_SPACER: { DEFAULT_BORDER_BOTTOM_WIDTH: 1, DEFAULT_MARGIN_VERTICAL: 8, HIDDEN_MARGIN_VERTICAL: 0, HIDDEN_BORDER_BOTTOM_WIDTH: 0, }, + + GLOBAL_NAVIGATION_OPTION: { + HOME: 'home', + CHATS: 'chats', + SPEND: 'spend', + WORKSPACES: 'workspaces', + }, + + MISSING_TRANSLATION: 'MISSING TRANSLATION', } as const; export default CONST; diff --git a/src/GLOBAL_NAVIGATION_MAPPING.ts b/src/GLOBAL_NAVIGATION_MAPPING.ts new file mode 100644 index 000000000000..f879c508ff31 --- /dev/null +++ b/src/GLOBAL_NAVIGATION_MAPPING.ts @@ -0,0 +1,9 @@ +import CONST from './CONST'; +import SCREENS from './SCREENS'; + +export default { + [CONST.GLOBAL_NAVIGATION_OPTION.HOME]: [SCREENS.HOME_OLDDOT], + [CONST.GLOBAL_NAVIGATION_OPTION.CHATS]: [SCREENS.REPORT], + [CONST.GLOBAL_NAVIGATION_OPTION.SPEND]: [SCREENS.EXPENSES_OLDDOT, SCREENS.REPORTS_OLDDOT, SCREENS.INSIGHTS_OLDDOT], + [CONST.GLOBAL_NAVIGATION_OPTION.WORKSPACES]: [SCREENS.INDIVIDUAL_WORKSPACES_OLDDOT, SCREENS.GROUPS_WORKSPACES_OLDDOT, SCREENS.CARDS_AND_DOMAINS_OLDDOT], +} as const; diff --git a/src/ROUTES.ts b/src/ROUTES.ts index b2dafa643b22..2b64dd9c5465 100644 --- a/src/ROUTES.ts +++ b/src/ROUTES.ts @@ -318,4 +318,17 @@ export default { // These are some on-off routes that will be removed once they're no longer needed (see GH issues for details) SAASTR: 'saastr', SBE: 'sbe', + + // Iframe screens from olddot + HOME_OLDDOT: 'home', + + // Spend tab + EXPENSES_OLDDOT: 'expenses', + REPORTS_OLDDOT: 'reports', + INSIGHTS_OLDDOT: 'insights', + + // Workspaces tab + INDIVIDUALS_OLDDOT: 'individual_workspaces', + GROUPS_OLDDOT: 'group_workspaces', + CARDS_AND_DOMAINS_OLDDOT: 'cards-and-domains', } as const; diff --git a/src/SCREENS.ts b/src/SCREENS.ts index eb125a43c239..0346168f0407 100644 --- a/src/SCREENS.ts +++ b/src/SCREENS.ts @@ -24,4 +24,17 @@ export default { SIGN_IN_WITH_APPLE_DESKTOP: 'AppleSignInDesktop', SIGN_IN_WITH_GOOGLE_DESKTOP: 'GoogleSignInDesktop', DESKTOP_SIGN_IN_REDIRECT: 'DesktopSignInRedirect', + + // Iframe screens from olddot + HOME_OLDDOT: 'Home_OLDDOT', + + // Spend tab + EXPENSES_OLDDOT: 'Expenses_OLDDOT', + REPORTS_OLDDOT: 'Reports_OLDDOT', + INSIGHTS_OLDDOT: 'Insights_OLDDOT', + + // Workspaces tab + INDIVIDUAL_WORKSPACES_OLDDOT: 'IndividualWorkspaces_OLDDOT', + GROUPS_WORKSPACES_OLDDOT: 'GroupWorkspaces_OLDDOT', + CARDS_AND_DOMAINS_OLDDOT: 'CardsAndDomains_OLDDOT', } as const; diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js index df49afbc3f0b..71d331b68db0 100644 --- a/src/components/ArchivedReportFooter.js +++ b/src/components/ArchivedReportFooter.js @@ -14,7 +14,6 @@ import reportPropTypes from '../pages/reportPropTypes'; import * as ReportActionsUtils from '../libs/ReportActionsUtils'; import styles from '../styles/styles'; import * as PersonalDetailsUtils from '../libs/PersonalDetailsUtils'; -import ArchivedReportFooterSkeletonView from './ArchivedReportFooterSkeletonView'; const propTypes = { /** The reason this report was archived */ @@ -51,9 +50,6 @@ const defaultProps = { }; function ArchivedReportFooter(props) { - if (!props.reportClosedAction.reportActionID) { - return ; - } const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT); let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [props.report.ownerAccountID, 'displayName']); diff --git a/src/components/ArchivedReportFooterSkeletonView.js b/src/components/ArchivedReportFooterSkeletonView.js deleted file mode 100644 index 5fbc3c9d9e2c..000000000000 --- a/src/components/ArchivedReportFooterSkeletonView.js +++ /dev/null @@ -1,48 +0,0 @@ -import PropTypes from 'prop-types'; -import React from 'react'; -import SkeletonViewContentLoader from 'react-content-loader/native'; -import {View} from 'react-native'; -import {Rect} from 'react-native-svg'; -import compose from '../libs/compose'; -import styles from '../styles/styles'; -import themeColors from '../styles/themes/default'; -import withLocalize from './withLocalize'; -import withWindowDimensions from './withWindowDimensions'; - -const propTypes = { - /** Whether to animate the skeleton view */ - shouldAnimate: PropTypes.bool, -}; - -const defaultTypes = { - shouldAnimate: true, -}; - -function ArchivedReportFooterSkeletonView(props) { - return ( - - - - - - ); -} - -ArchivedReportFooterSkeletonView.propTypes = propTypes; -ArchivedReportFooterSkeletonView.defaultProps = defaultTypes; - -ArchivedReportFooterSkeletonView.displayName = 'ArchivedReportFooterSkeletonView'; -export default compose(withWindowDimensions, withLocalize)(ArchivedReportFooterSkeletonView); diff --git a/src/components/AutoUpdateTime.js b/src/components/AutoUpdateTime.js index cb15cb20b4ea..e7d8b133e903 100644 --- a/src/components/AutoUpdateTime.js +++ b/src/components/AutoUpdateTime.js @@ -24,7 +24,7 @@ const propTypes = { function AutoUpdateTime(props) { /** - * @returns {moment} Returns the locale moment object + * @returns {Date} Returns the locale Date object */ const getCurrentUserLocalTime = useCallback( () => DateUtils.getLocalDateFromDatetime(props.preferredLocale, null, props.timezone.selected), diff --git a/src/components/BaseMiniContextMenuItem.js b/src/components/BaseMiniContextMenuItem.js index 0e9085b54c17..c5c0892324c3 100644 --- a/src/components/BaseMiniContextMenuItem.js +++ b/src/components/BaseMiniContextMenuItem.js @@ -61,6 +61,12 @@ function BaseMiniContextMenuItem(props) { return; } + // Allow text input blur on right click + if (!e || e.button === 2) { + return; + } + + // Prevent text input blur on left click e.preventDefault(); }} accessibilityLabel={props.tooltipText} diff --git a/src/components/Checkbox.js b/src/components/Checkbox.js index 394e73951c09..b4ffd7a6b062 100644 --- a/src/components/Checkbox.js +++ b/src/components/Checkbox.js @@ -91,7 +91,7 @@ function Checkbox(props) { onPress={firePressHandlerOnClick} onMouseDown={props.onMouseDown} ref={props.forwardedRef} - style={[props.style, StyleUtils.getCheckboxPressableStyle(props.containerBorderRadius + 2)]} // to align outline on focus, border-radius of pressable should be 2px more than Checkbox + style={[StyleUtils.getCheckboxPressableStyle(props.containerBorderRadius + 2), props.style]} // to align outline on focus, border-radius of pressable should be 2px more than Checkbox onKeyDown={handleSpaceKey} accessibilityRole={CONST.ACCESSIBILITY_ROLE.CHECKBOX} accessibilityState={{checked: props.isChecked}} @@ -108,6 +108,7 @@ function Checkbox(props) { props.isChecked && styles.checkedContainer, props.hasError && styles.borderColorDanger, props.disabled && styles.cursorDisabled, + props.disabled && styles.buttonOpacityDisabled, props.isChecked && styles.borderColorFocus, ]} > diff --git a/src/components/CheckboxWithLabel.js b/src/components/CheckboxWithLabel.js index 18ad0880b92c..63c067c93234 100644 --- a/src/components/CheckboxWithLabel.js +++ b/src/components/CheckboxWithLabel.js @@ -102,6 +102,7 @@ function CheckboxWithLabel(props) { isChecked={isChecked} onPress={toggleCheckbox} label={props.label} + style={[styles.checkboxWithLabelCheckboxStyle]} hasError={Boolean(props.errorText)} forwardedRef={props.forwardedRef} accessibilityLabel={props.accessibilityLabel || props.label} diff --git a/src/components/EnvironmentBadge.js b/src/components/EnvironmentBadge.js index af118a37f3b4..a83fcedfabe4 100644 --- a/src/components/EnvironmentBadge.js +++ b/src/components/EnvironmentBadge.js @@ -28,7 +28,7 @@ function EnvironmentBadge() { success={environment === CONST.ENVIRONMENT.STAGING || environment === CONST.ENVIRONMENT.ADHOC} error={environment !== CONST.ENVIRONMENT.STAGING && environment !== CONST.ENVIRONMENT.ADHOC} text={text} - badgeStyles={[styles.alignSelfEnd, styles.headerEnvBadge]} + badgeStyles={[styles.alignSelfEnd, styles.headerEnvBadge, styles.ml1]} textStyles={[styles.headerEnvBadgeText]} environment={environment} /> diff --git a/src/components/FloatingActionButton.js b/src/components/FloatingActionButton.js index f1174988e955..d6f5b907ace0 100644 --- a/src/components/FloatingActionButton.js +++ b/src/components/FloatingActionButton.js @@ -9,6 +9,7 @@ import themeColors from '../styles/themes/default'; import Tooltip from './Tooltip'; import withLocalize, {withLocalizePropTypes} from './withLocalize'; import PressableWithFeedback from './Pressable/PressableWithFeedback'; +import variables from '../styles/variables'; const AnimatedIcon = Animated.createAnimatedComponent(Icon); AnimatedIcon.displayName = 'AnimatedIcon'; @@ -100,6 +101,8 @@ class FloatingActionButton extends PureComponent { style={[styles.floatingActionButton, StyleUtils.getAnimatedFABStyle(rotate, backgroundColor)]} > diff --git a/src/components/IFrame.js b/src/components/IFrame.js new file mode 100644 index 000000000000..5f7f657b0c09 --- /dev/null +++ b/src/components/IFrame.js @@ -0,0 +1,134 @@ +/* eslint-disable es/no-nullish-coalescing-operators */ +import React, {useEffect, useState} from 'react'; +import {withOnyx} from 'react-native-onyx'; +import PropTypes from 'prop-types'; +import ONYXKEYS from '../ONYXKEYS'; + +function getNewDotURL(url) { + const urlObj = new URL(url); + const paramString = urlObj.searchParams.get('param') ?? ''; + const pathname = urlObj.pathname.slice(1); + + let params; + try { + params = JSON.parse(paramString); + } catch { + params = {}; + } + + if (pathname === 'inbox') { + return 'home'; + } + + if (pathname === 'expenses') { + return `${params.viewMode === 'charts' ? 'insights' : 'expenses'}${paramString ? `/?param=${paramString}` : ''}`; + } + + if (pathname === 'admin_policies') { + const {section} = params; + return section === 'individual' ? 'individual_workspaces' : 'group_workspaces'; + } + + if (pathname === 'policy') { + const workspaceID = params.policyID || ''; + const section = urlObj.hash.slice(1) || 'overview'; + + return `workspace/${workspaceID}/${section}`; + } + + if (pathname === 'settings') { + const {section} = params; + return `settings/${section}`; + } + + if (pathname.includes('domain')) { + return pathname; + } + + return pathname; +} + +function getOldDotURL(url) { + const urlObj = new URL(url); + const pathname = urlObj.pathname; + const paths = pathname.slice(1).split('/'); + + // TODO: temporary measure until linking config is adjusted + if (pathname.startsWith('/r')) { + return 'inbox'; + } + + if (pathname === 'home') { + return 'inbox'; + } + + if (pathname === 'expenses' || pathname === 'insights') { + return `expenses/${urlObj.search}`; + } + + if (pathname === 'individual_workspaces' || pathname === 'group_workspaces') { + const param = {section: pathname === 'individual_workspaces' ? 'individual' : 'group'}; + return `admin_policies?param=${JSON.stringify(param)}`; + } + + if (pathname === 'workspace') { + const [, workspaceID, section] = paths; + const param = {policyID: workspaceID}; + return `policy/?param${JSON.stringify(param)}#${section}`; + } + + if (pathname === 'settings') { + const [, section] = paths; + const param = {section}; + return `settings?param=${JSON.stringify(param)}`; + } + + return pathname; +} + +const propTypes = { + // The session of the logged in person + session: PropTypes.shape({ + // The email of the logged in person + email: PropTypes.string, + + // The authToken of the logged in person + authToken: PropTypes.string, + }).isRequired, +}; + +function OldDotIFrame({session}) { + const [oldDotURL, setOldDotURL] = useState('https://staging.expensify.com'); + + useEffect(() => { + setOldDotURL(`https://expensify.com.dev/${getOldDotURL(window.location.href)}`); + + window.addEventListener('message', (event) => { + const url = event.data; + // TODO: use this value to navigate to a new path + // eslint-disable-next-line no-unused-vars + const newDotURL = getNewDotURL(url); + }); + }, []); + + useEffect(() => { + document.cookie = `authToken=${session.authToken}; domain=expensify.com.dev; path=/;`; + document.cookie = `email=${session.email}; domain=expensify.com.dev; path=/;`; + }, [session.authToken, session.email]); + + return ( +