- {% for article in section.articles %}
+ {% assign sortedArticles = section.articles | sort: 'order', 'last' | default: 999 %}
+ {% for article in sortedArticles %}
{% assign article_href = section.href | append: '/' | append: article.href %}
{% include article-card.html hub=hub.href href=article_href title=article.title platform=activePlatform %}
{% endfor %}
diff --git a/docs/articles/expensify-classic/connect-credit-cards/company-cards/Troubleshooting.md b/docs/articles/expensify-classic/connect-credit-cards/company-cards/Troubleshooting.md
index 05366a91d9fa..f94e692f5e56 100644
--- a/docs/articles/expensify-classic/connect-credit-cards/company-cards/Troubleshooting.md
+++ b/docs/articles/expensify-classic/connect-credit-cards/company-cards/Troubleshooting.md
@@ -8,6 +8,15 @@ Whether you're encountering issues related to company cards, require assistance
## How to add company cards to Expensify
You can add company credit cards under the Domain settings in your Expensify account by navigating to *Settings* > *Domain* > _Domain Name_ > *Company Cards* and clicking *Import Card/Bank* and following the prompts.
+## To Locate Missing Card Transactions in Expensify
+1. **Wait for Posting**: Bank transactions may take up to 24 hours to import into Expensify after they have "posted" at your bank. Ensure sufficient time has passed for transactions to appear.
+2. **Update Company Cards**: Go to Settings > Domains > Company Cards. Click on the card in question and click "Update" to refresh the card feed.
+3. **Reconcile Cards**: Navigate to the Reconciliation section under Settings > Domains > Company Cards. Refer to the detailed guide on how to use the [Reconciliation Dashboard](https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/Reconciliation#identifying-outstanding-unapproved-expenses-using-the-reconciliation-dashboard).
+4. **Review Transactions**: Use the Reconciliation Dashboard to view all transactions within a specific timeframe. Transactions will display on the Expenses page based on their "Posted Date". If needed, uncheck the "use posted date" checkbox near the filters to view transactions based on their "Transaction Date" instead.
+5. **Address Gaps**: If there is a significant gap in transactions or if transactions are still missing, contact Expensify's Concierge or your Account Manager. They can initiate a historical data update on your card feed to ensure all transactions are properly imported.
+
+Following these steps should help you identify and resolve any issues with missing card transactions in Expensify.
+
## Known issues importing transactions
The first step should always be to "Update" your card, either from Settings > Your Account > Credit Card Import or Settings > Domain > [Domain Name] > Company Cards for centrally managed cards. If a "Fix" or "Fix card" option appears, follow the steps to fix the connection. If this fails to import your missing transactions, there is a known issue whereby some transactions will not import for certain API-based company card connections. So far this has been reported on American Express, Chase and Wells Fargo. This can be temporarily resolved by creating the expenses manually instead:
@@ -63,6 +72,24 @@ If you've answered "yes" to any of these questions, a Domain Admins need to upda
Make sure you're importing your card in the correct spot in Expensify and selecting the right bank connection. For company cards, use the master administrative credentials to import your set of cards at *Settings* > *Domains* > _Domain Name_ > *Company Cards* > *Import Card*.
Please note there are some things that cannot be bypassed within Expensify, including two-factor authentication being enabled within your bank account. This will prevent the connection from remaining stable and will need to be turned off on the bank side.
+## Why Can’t I See the Transactions Before a Certain Date?
+When importing a card into Expensify, the platform typically retrieves 30-90 days of historical transactions, depending on the card or account type. For commercial feeds, transactions cannot be imported before the bank starts sending data. If needed, banks can send backdated files, and Expensify can run a historical update upon request.
+
+Additionally, Expensify does not import transactions dated before the "start date" you specify when assigning the card. Unless transitioning from an old card to a new one to avoid duplicates, it's advisable to set the start date to "earliest possible" or leave it blank.
+
+For historical expenses that cannot be imported automatically, consider using Expensify's [company card](https://help.expensify.com/articles/expensify-classic/connect-credit-cards/company-cards/CSV-Import) or [personal card](https://help.expensify.com/articles/expensify-classic/connect-credit-cards/Personal-Credit-Cards#importing-expenses-via-a-spreadsheet) spreadsheet import method. This allows you to manually input missing transactions into the system.
+
+## Why Am I / Why Is My Employee Seeing Duplicates?
+If an employee is seeing duplicate expenses, they may have accidentally imported the card as a personal credit card as well as having the Domain Admin assign them a company card.
+
+To troubleshoot:
+- Have the employee navigate to their Settings > Your Account > Credit Card Import and confirm that their card is only listed once.
+- If the card is listed twice, delete the entry without the "padlock" icon.
+
+**Important:** Deleting a duplicate card will delete all unapproved expenses from that transaction feed. Transactions associated with the remaining card will not be affected. If receipts were attached to those transactions, they will still be on the Expenses page, and the employee can click to SmartScan them again.
+
+Duplicate expenses might also occur if you recently unassigned and reassigned a company card with an overlapping start date. If this is the case and expenses on the “new” copy have not been submitted, you can unassign the card again and reassign it with a more appropriate start date. This action will delete all unsubmitted expenses from the new card feed.
+
## What are the most reliable bank connections in Expensify?*
All bank connections listed below are extremely reliable, but we recommend transacting with the Expensify Visa® Commercial Card. It also offers daily and monthly settlement, unapproved expense limits, realtime compliance for secure and efficient spending, and cash back on all US purchases. [Click here to learn more about the Expensify Card](https://use.expensify.com/company-credit-card).
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/ADP.md b/docs/articles/expensify-classic/connections/ADP.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/HR-integrations/ADP.md
rename to docs/articles/expensify-classic/connections/ADP.md
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations.md b/docs/articles/expensify-classic/connections/Additional-Travel-Integrations.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations.md
rename to docs/articles/expensify-classic/connections/Additional-Travel-Integrations.md
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Egencia.md b/docs/articles/expensify-classic/connections/Egencia.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/travel-integrations/Egencia.md
rename to docs/articles/expensify-classic/connections/Egencia.md
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Global-VaTax.md b/docs/articles/expensify-classic/connections/Global-VaTax.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/travel-integrations/Global-VaTax.md
rename to docs/articles/expensify-classic/connections/Global-VaTax.md
diff --git a/docs/articles/expensify-classic/integrations/other-integrations/Google-Apps-SSO.md b/docs/articles/expensify-classic/connections/Google-Apps-SSO.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/other-integrations/Google-Apps-SSO.md
rename to docs/articles/expensify-classic/connections/Google-Apps-SSO.md
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/Greenhouse.md b/docs/articles/expensify-classic/connections/Greenhouse.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/HR-integrations/Greenhouse.md
rename to docs/articles/expensify-classic/connections/Greenhouse.md
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/Gusto.md b/docs/articles/expensify-classic/connections/Gusto.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/HR-integrations/Gusto.md
rename to docs/articles/expensify-classic/connections/Gusto.md
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Indirect-Accounting-Integrations.md b/docs/articles/expensify-classic/connections/Indirect-Accounting-Integrations.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/accounting-integrations/Indirect-Accounting-Integrations.md
rename to docs/articles/expensify-classic/connections/Indirect-Accounting-Integrations.md
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Lyft.md b/docs/articles/expensify-classic/connections/Lyft.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/travel-integrations/Lyft.md
rename to docs/articles/expensify-classic/connections/Lyft.md
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Navan.md b/docs/articles/expensify-classic/connections/Navan.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/travel-integrations/Navan.md
rename to docs/articles/expensify-classic/connections/Navan.md
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/QuickBooks-Time.md b/docs/articles/expensify-classic/connections/QuickBooks-Time.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/HR-integrations/QuickBooks-Time.md
rename to docs/articles/expensify-classic/connections/QuickBooks-Time.md
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/Rippling.md b/docs/articles/expensify-classic/connections/Rippling.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/HR-integrations/Rippling.md
rename to docs/articles/expensify-classic/connections/Rippling.md
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/TravelPerk.md b/docs/articles/expensify-classic/connections/TravelPerk.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/travel-integrations/TravelPerk.md
rename to docs/articles/expensify-classic/connections/TravelPerk.md
diff --git a/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md b/docs/articles/expensify-classic/connections/Uber.md
similarity index 90%
rename from docs/articles/expensify-classic/integrations/travel-integrations/Uber.md
rename to docs/articles/expensify-classic/connections/Uber.md
index 16da0c0caa5b..213a90b6d288 100644
--- a/docs/articles/expensify-classic/integrations/travel-integrations/Uber.md
+++ b/docs/articles/expensify-classic/connections/Uber.md
@@ -22,3 +22,5 @@ Now, every time you use Uber for Business – be it for rides or meals – the r
![Uber integration set up steps: Connecting your account](https://help.expensify.com/assets/images/Uber1.png){:width="100%"}
![Uber integration set up steps: Selecting Expensify](https://help.expensify.com/assets/images/Uber2.png){:width="100%"}
+
+To disconnect Uber and Expensify, simply follow the above path and select Disconnect on the Expensify option.
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/Workday.md b/docs/articles/expensify-classic/connections/Workday.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/HR-integrations/Workday.md
rename to docs/articles/expensify-classic/connections/Workday.md
diff --git a/docs/articles/expensify-classic/integrations/HR-integrations/Zenefits.md b/docs/articles/expensify-classic/connections/Zenefits.md
similarity index 100%
rename from docs/articles/expensify-classic/integrations/HR-integrations/Zenefits.md
rename to docs/articles/expensify-classic/connections/Zenefits.md
diff --git a/docs/articles/expensify-classic/connections/accelo/Accelo-Troubleshooting.md b/docs/articles/expensify-classic/connections/accelo/Accelo-Troubleshooting.md
new file mode 100644
index 000000000000..fd0a6ca59069
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/accelo/Accelo-Troubleshooting.md
@@ -0,0 +1,7 @@
+---
+title: Accelo Troubleshooting
+description: Accelo Troubleshooting
+order: 3
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/connections/accelo/Configure-Accelo.md b/docs/articles/expensify-classic/connections/accelo/Configure-Accelo.md
new file mode 100644
index 000000000000..abb14767b196
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/accelo/Configure-Accelo.md
@@ -0,0 +1,7 @@
+---
+title: Configure Accelo
+description: Configure Accelo
+order: 2
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Accelo.md b/docs/articles/expensify-classic/connections/accelo/Connect-To-Accelo.md
similarity index 99%
rename from docs/articles/expensify-classic/integrations/accounting-integrations/Accelo.md
rename to docs/articles/expensify-classic/connections/accelo/Connect-To-Accelo.md
index fffe0abb43aa..96b0a17a1528 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Accelo.md
+++ b/docs/articles/expensify-classic/connections/accelo/Connect-To-Accelo.md
@@ -1,6 +1,7 @@
---
title: Accelo
description: Help doc for Accelo integration
+order: 1
---
diff --git a/docs/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting.md b/docs/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting.md
new file mode 100644
index 000000000000..82a2762ee99a
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/certinia/Certinia-Troubleshooting.md
@@ -0,0 +1,6 @@
+---
+title: Certinia Troubleshooting
+description: Certinia Troubleshooting
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/connections/certinia/Configure-Certinia.md b/docs/articles/expensify-classic/connections/certinia/Configure-Certinia.md
new file mode 100644
index 000000000000..dc7398c11888
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/certinia/Configure-Certinia.md
@@ -0,0 +1,7 @@
+---
+title: Configure Certinia
+description: Configure Certinia
+order: 2
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Certinia.md b/docs/articles/expensify-classic/connections/certinia/Connect-To-Certinia.md
similarity index 99%
rename from docs/articles/expensify-classic/integrations/accounting-integrations/Certinia.md
rename to docs/articles/expensify-classic/connections/certinia/Connect-To-Certinia.md
index 6c7014827ea6..5e5174a336b3 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Certinia.md
+++ b/docs/articles/expensify-classic/connections/certinia/Connect-To-Certinia.md
@@ -1,6 +1,7 @@
---
title: Certinia
description: Guide to connecting Expensify and Certinia FFA and PSA/SRP (formerly known as FinancialForce)
+order: 1
---
# Overview
[Cetinia](https://use.expensify.com/financialforce) (formerly known as FinancialForce) is a cloud-based software solution that provides a range of financial management and accounting applications built on the Salesforce platform. There are two versions: PSA/SRP and FFA and we support both.
diff --git a/docs/articles/expensify-classic/connections/netsuite/Configure-Netsuite.md b/docs/articles/expensify-classic/connections/netsuite/Configure-Netsuite.md
new file mode 100644
index 000000000000..e14a4cab21d6
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/netsuite/Configure-Netsuite.md
@@ -0,0 +1,6 @@
+---
+title: Configure Netsuite
+description: Configure Netsuite
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/connections/netsuite/Connect-To-NetSuite.md b/docs/articles/expensify-classic/connections/netsuite/Connect-To-NetSuite.md
new file mode 100644
index 000000000000..1f96d9b8a633
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/netsuite/Connect-To-NetSuite.md
@@ -0,0 +1,164 @@
+---
+title: NetSuite
+description: Set up the direct connection from Expensify to NetSuite.
+order: 1
+---
+# Overview
+Expensify's integration with NetSuite allows you to automate report exports, tailor your coding preferences, and tap into NetSuite's array of advanced features. By correctly configuring your NetSuite settings in Expensify, you can leverage the connection's settings to automate most of the tasks, making your workflow more efficient.
+
+**Before connecting NetSuite to Expensify, a few things to note:**
+- Token-based authentication works by ensuring that each request to NetSuite is accompanied by a signed token which is verified for authenticity
+- You must be able to login to NetSuite as an administrator to initiate the connection
+- You must have a Control Plan in Expensify to integrate with NetSuite
+- Employees don’t need NetSuite access or a NetSuite license to submit expense reports since the connection is managed by the Workspace Admin
+- Each NetSuite subsidiary will need its own Expensify Group Workspace
+- Ensure that your workspace's report output currency setting matches the NetSuite Subsidiary default currency
+- Make sure your page size is set to 1000 for importing your customers and vendors. You can check this in NetSuite under **Setup > Integration > Web Services Preferences > 'Search Page Size'**
+
+# Connect to NetSuite
+
+## Step 1: Install the Expensify Bundle in NetSuite
+
+1. While logged into NetSuite as an administrator, go to Customization > SuiteBundler > Search & Install Bundles, then search for "Expensify"
+2. Click on the Expensify Connect bundle (Bundle ID 283395)
+3. Click Install
+4. If you already have the Expensify Connect bundle installed, head to _Customization > SuiteBundler > Search & Install Bundles > List_ and update it to the latest version
+5. Select **Show on Existing Custom Forms** for all available fields
+
+## Step 2: Enable Token-Based Authentication
+
+1. Head to _Setup > Company > Enable Features > SuiteCloud > Manage Authentication_
+2. Make sure “Token Based Authentication” is enabled
+3. Click **Save**
+
+## Step 3: Add Expensify Integration Role to a User
+
+The user you select must have access to at least the permissions included in the Expensify Integration Role, but they're not required to be an Admin.
+1. In NetSuite, head to Lists > Employees, and find the user you want to add the Expensify Integration role to
+2. Click _Edit > Access_, then find the Expensify Integration role in the dropdown and add it to the user
+3. Click **Save**
+
+Remember that Tokens are linked to a User and a Role, not solely to a User. It's important to note that you cannot establish a connection with tokens using one role and then switch to another role afterward. Once you've initiated a connection with tokens, you must continue using the same token/user/role combination for all subsequent sync or export actions.
+
+## Step 4: Create Access Tokens
+
+1. Using Global Search in NetSuite, enter “page: tokens”
+2. Click **New Access Token**
+3. Select Expensify as the application (this must be the original Expensify integration from the bundle)
+4. Select the role Expensify Integration
+5. Press **Save**
+6. Copy and Paste the token and token ID to a saved location on your computer (this is the only time you will see these details)
+
+## Step 5: Confirm Expense Reports are Enabled in NetSuite.
+
+Enabling Expense Reports is required as part of Expensify's integration with NetSuite:
+1. Logged into NetSuite as an administrator, go to Setup > Company > Enable Features > Employees
+2. Confirm the checkbox next to Expense Reports is checked
+3. If not, click the checkbox and then Save to enable Expense Reports
+
+## Step 6: Confirm Expense Categories are set up in NetSuite.
+
+Once Expense Reports are enabled, Expense Categories can be set up in NetSuite. Expense Categories are an alias for General Ledger accounts used to code expenses.
+
+1. Logged into NetSuite as an administrator, go to Setup > Accounting > Expense Categories (a list of Expense Categories should show)
+2. If no Expense Categories are visible, click **New** to create new ones
+
+## Step 7: Confirm Journal Entry Transaction Forms are Configured Properly
+
+1. Logged into NetSuite as an administrator, go to _Customization > Forms > Transaction Forms_
+2. Click **Customize** or **Edit** next to the Standard Journal Entry form
+3. Then, click Screen Fields > Main. Please verify the "Created From" label has "Show" checked and the Display Type is set to Normal
+4. Click the sub-header Lines and verify that the "Show" column for "Receipt URL" is checked
+5. Go to _Customization > Forms > Transaction Forms_ and ensure all other transaction forms with the journal type have this same configuration
+
+## Step 8: Confirm Expense Report Transaction Forms are Configured Properly
+
+1. Logged into NetSuite as an administrator, go to _Customization > Forms > Transaction Forms_
+2. Click **Customize** or **Edit** next to the Standard Expense Report form, then click **Screen Fields > Main**
+3. Verify the "Created From" label has "Show" checked and the Display Type is set to Normal
+4. Click the second sub-header, Expenses, and verify that the 'Show' column for 'Receipt URL' is checked
+5. Go to _Customization > Forms > Transaction Forms_ and ensure all other transaction forms with the expense report type have this same configuration
+
+## Step 9: Confirm Vendor Bill Transactions Forms are Configured Properly
+
+1. Logged into NetSuite as an administrator, go to _Customization > Forms > Transaction Forms_
+2. Click **Customize** or **Edit** next to your preferred Vendor Bill form
+3. Then, click _Screen Fields > Main_ and verify that the "Created From" label has "Show" checked and that Departments, Classes, and Locations have the "Show" label unchecked
+4. Under the Expenses sub-header (make sure to click the "Expenses" sub-header at the very bottom and not "Expenses & Items"), ensure "Show" is checked for Receipt URL, Department, Location, and Class
+5. Go to _Customization > Forms > Transaction Forms_ and provide all other transaction forms with the vendor bill type have this same configuration
+
+## Step 10: Confirm Vendor Credit Transactions Forms are Configured Properly
+
+1. While logged in as an administrator, go to _Customization > Forms > Transaction Forms_
+2. Click **Customize** or **Edit** next to your preferred Vendor Credit form, then click _Screen Fields > Main_ and verify that the "Created From" label has "Show" checked and that Departments, Classes, and Locations have the "Show" label unchecked
+3. Under the Expenses sub-header (make sure to click the "Expenses" sub-header at the very bottom and not "Expenses & Items"), ensure "Show" is checked for Receipt URL, Department, Location, and Class
+4. Go to _Customization > Forms > Transaction Forms_ and ensure all other transaction forms with the vendor credit type have this same configuration
+
+## Step 11: Set up Tax Groups (only applicable if tracking taxes)
+
+Expensify imports NetSuite Tax Groups (not Tax Codes), which you can find in NetSuite under _Setup > Accounting > Tax Groups_.
+
+Tax Groups are an alias for Tax Codes in NetSuite and can contain one or more Tax Codes (Please note: for UK and Ireland subsidiaries, please ensure your Tax Groups do not have more than one Tax Code). We recommend naming Tax Groups so your employees can easily understand them, as the name and rate will be displayed in Expensify.
+
+Before importing NetSuite Tax Groups into Expensify:
+1. Create your Tax Groups in NetSuite by going to _Setup > Accounting > Tax Groups_
+2. Click **New**
+3. Select the country for your Tax Group
+4. Enter the Tax Name (this is what employees will see in Expensify)
+5. Select the subsidiary for this Tax Group
+6. Select the Tax Code from the table you wish to include in this Tax Group
+7. Click **Add**
+8. Click **Save**
+9. Create one NetSuite Tax Group for each tax rate you want to show in Expensify
+
+Ensure Tax Groups can be applied to expenses by going to _Setup > Accounting > Set Up Taxes_ and setting the Tax Code Lists Include preference to "Tax Groups And Tax Codes" or "Tax Groups Only."
+
+If this field does not display, it’s not needed for that specific country.
+
+## Step 12: Connect Expensify and NetSuite
+
+1. Log into Expensify as a Policy Admin and go to **Settings > Workspaces > _[Workspace Name]_ > Connections > NetSuite**
+2. Click **Connect to NetSuite**
+3. Enter your Account ID (Account ID can be found in NetSuite by going to _Setup > Integration > Web Services Preferences_)
+4. Then, enter the token and token secret
+5. Click **Connect to NetSuite**
+
+From there, the NetSuite connection will sync, and the configuration dialogue box will appear.
+
+Please note that you must create the connection using a NetSuite account with the Expensify Integration role
+
+Once connected, all reports exported from Expensify will be generated in NetSuite using SOAP Web Services (the term NetSuite employs when records are created through the integration).
+
+{% include faq-begin.md %}
+
+## Can negative expenses be exported to NetSuite?
+You can export reports with a negative total to NetSuite by selecting “Vendor Bill” as your export option. When a report total is negative, we’ll create a Vendor Credit in NetSuite instead of a bill.
+
+**Important**: Only enable this if you pay your employees/vendors outside of Expensify. A Vendor Credit reduces the total amount payable in NetSuite, but not in Expensify.
+
+To use this feature, make sure you have configured your Vendor Credit transaction form in NetSuite and are using the latest version of the Expensify bundle (version 1.4). If you need to update, go to **Customization > SuiteBundler > Search & Install Bundles > List** and click **Update** next to **Expensify Connect**.
+
+## How do you switch the owner of the connection between NetSuite and Expensify?
+
+Follow the steps below to transfer ownership of the NetSuite connection to someone else:
+1. Head to **Settings > Workspaces > Workspace Name > Connections > NetSuite**
+2. Click **Configure** to review and save the settings for future reference
+3. Select **Do not connect to NetSuite**
+4. Select **Connect to NetSuite**
+5. Enter the email address of the new admin who will take over as the NetSuite User ID
+6. Enter the NetSuite Account ID (found in NetSuite under **Setup > Integration > Web Services Preferences**)
+7. Click **Create a new NetSuite Connection**
+8. Confirm completion of prerequisites and proceed by clicking Continue
+9. You will be redirected to the NetSuite SSO page, where you will enter the email address of the new connection owner and the NetSuite password for that account
+10. Once redirected to the NetSuite page, click **View all roles** and ensure you are logged in under the Administrator role
+11. After confirmation, sign out
+12. Return to Expensify to reconfigure the sync and export settings on the updated connection
+13. Click **Save**
+
+**If you run into any issues updating the connection, follow these additional troubleshooting steps:**
+- In NetSuite, access the role of the current connection owner
+- Click Edit > Access > Choose any role other than Administrator > Save
+- Click Edit > Access > Select Administrator role > Save
+- Repeat the steps outlined above
+
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting.md b/docs/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting.md
new file mode 100644
index 000000000000..698aaead045b
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/netsuite/Netsuite-Troubleshooting.md
@@ -0,0 +1,6 @@
+---
+title: Netsuite Troubleshooting
+description: Netsuite Troubleshooting
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Configure-Quickbooks-Desktop.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Configure-Quickbooks-Desktop.md
new file mode 100644
index 000000000000..eda92d41e820
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/quickbooks-desktop/Configure-Quickbooks-Desktop.md
@@ -0,0 +1,6 @@
+---
+title: Configure Quickbooks Desktop
+description: Configure Quickbooks Desktop
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop.md
similarity index 99%
rename from docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
rename to docs/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop.md
index 8fe31f3ec4f4..cd0b23d327d7 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
+++ b/docs/articles/expensify-classic/connections/quickbooks-desktop/Connect-To-QuickBooks-Desktop.md
@@ -1,6 +1,7 @@
---
title: QuickBooks Desktop
description: How to connect Expensify to QuickBooks Desktop and troubleshoot issues.
+order: 1
---
# 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.
diff --git a/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md b/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md
new file mode 100644
index 000000000000..cdbba9ec0b23
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/quickbooks-desktop/Quickbooks-Desktop-Troubleshooting.md
@@ -0,0 +1,6 @@
+---
+title: Quickbooks Desktop Troubleshooting
+description: Quickbooks Desktop Troubleshooting
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/connections/quickbooks-online/Configure-Quickbooks-Online.md b/docs/articles/expensify-classic/connections/quickbooks-online/Configure-Quickbooks-Online.md
new file mode 100644
index 000000000000..99e598adb06a
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/quickbooks-online/Configure-Quickbooks-Online.md
@@ -0,0 +1,6 @@
+---
+title: Configure Quickbooks Online
+description: Configure Quickbooks Online
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md b/docs/articles/expensify-classic/connections/quickbooks-online/Connect-To-QuickBooks-Online.md
similarity index 99%
rename from docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md
rename to docs/articles/expensify-classic/connections/quickbooks-online/Connect-To-QuickBooks-Online.md
index 623e5f1dd997..1d536d7bdb66 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online.md
+++ b/docs/articles/expensify-classic/connections/quickbooks-online/Connect-To-QuickBooks-Online.md
@@ -1,6 +1,7 @@
---
title: QuickBooks Online
description: Everything you need to know about using Expensify's direct integration with QuickBooks Online.
+order: 1
---
# Overview
diff --git a/docs/articles/expensify-classic/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md b/docs/articles/expensify-classic/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
new file mode 100644
index 000000000000..7e58ad83a164
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/quickbooks-online/Quickbooks-Online-Troubleshooting.md
@@ -0,0 +1,6 @@
+---
+title: Quickbooks Online Troubleshooting
+description: Quickbooks Online Troubleshooting
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/connections/sage-intacct/Configure-Sage-Intacct.md b/docs/articles/expensify-classic/connections/sage-intacct/Configure-Sage-Intacct.md
new file mode 100644
index 000000000000..444825973161
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/sage-intacct/Configure-Sage-Intacct.md
@@ -0,0 +1,6 @@
+---
+title: Configure Sage Intacct
+description: Configure Sage Intacct
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md b/docs/articles/expensify-classic/connections/sage-intacct/Connect-To-Sage-Intacct.md
similarity index 99%
rename from docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md
rename to docs/articles/expensify-classic/connections/sage-intacct/Connect-To-Sage-Intacct.md
index 560a65d0d722..369c3aae9fa9 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct.md
+++ b/docs/articles/expensify-classic/connections/sage-intacct/Connect-To-Sage-Intacct.md
@@ -1,6 +1,7 @@
---
title: Sage Intacct
description: Connect your Expensify workspace with Sage Intacct
+order: 1
---
# Overview
Expensify’s seamless integration with Sage Intacct allows you to connect using either Role-based permissions or User-based permissions.
diff --git a/docs/articles/expensify-classic/connections/sage-intacct/Sage-Intacct-Troubleshooting.md b/docs/articles/expensify-classic/connections/sage-intacct/Sage-Intacct-Troubleshooting.md
new file mode 100644
index 000000000000..db341f87e930
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/sage-intacct/Sage-Intacct-Troubleshooting.md
@@ -0,0 +1,6 @@
+---
+title: Sage Intacct Troubleshooting
+description: Sage Intacct Troubleshooting
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/connections/xero/Configure-Xero.md b/docs/articles/expensify-classic/connections/xero/Configure-Xero.md
new file mode 100644
index 000000000000..b23216c28401
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/xero/Configure-Xero.md
@@ -0,0 +1,6 @@
+---
+title: Configure Xero
+description: Configure Xero
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md b/docs/articles/expensify-classic/connections/xero/Connect-To-Xero.md
similarity index 99%
rename from docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md
rename to docs/articles/expensify-classic/connections/xero/Connect-To-Xero.md
index 9dd479e90cf1..3010d11c2ff1 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/Xero.md
+++ b/docs/articles/expensify-classic/connections/xero/Connect-To-Xero.md
@@ -1,6 +1,7 @@
---
title: The Xero Integration
description: Everything you need to know about Expensify's direct integration with Xero
+order: 1
---
# About
diff --git a/docs/articles/expensify-classic/connections/xero/Xero-Troubleshooting.md b/docs/articles/expensify-classic/connections/xero/Xero-Troubleshooting.md
new file mode 100644
index 000000000000..98ae5033db50
--- /dev/null
+++ b/docs/articles/expensify-classic/connections/xero/Xero-Troubleshooting.md
@@ -0,0 +1,6 @@
+---
+title: Xero Troubleshooting
+description: Xero Troubleshooting
+---
+
+# Coming soon
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md b/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md
deleted file mode 100644
index ee116f65a398..000000000000
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/NetSuite.md
+++ /dev/null
@@ -1,579 +0,0 @@
----
-title: NetSuite
-description: Connect and configure NetSuite directly to Expensify.
----
-# Overview
-Expensify's seamless integration with NetSuite enables you to streamline your expense reporting process. This integration allows you to automate the export of reports, tailor your coding preferences, and tap into NetSuite's array of advanced features. By correctly configuring your NetSuite settings in Expensify, you can leverage the connection's settings to automate most of the tasks, making your workflow more efficient.
-
-Before getting started with connecting NetSuite to Expensify, there are a few things to note:
-- Token-based authentication works by ensuring that each request to NetSuite is accompanied by a signed token which is verified for authenticity
-- You must be able to login to NetSuite as an administrator to initiate the connection
-- You must have a Control Plan in Expensify to integrate with NetSuite
-- Employees don’t need NetSuite access or a NetSuite license to submit expense reports since the connection is managed by the Workspace Admin
-- Each NetSuite subsidiary will need its own Expensify Group Workspace
-- Ensure that your workspace's report output currency setting matches the NetSuite Subsidiary default currency
-- Make sure your page size is set to 1000 for importing your customers and vendors. Go to Setup > Integration > Web Services Preferences > 'Search Page Size'
-
-# How to Connect to NetSuite
-
-## Step 1: Install the Expensify Bundle in NetSuite
-
-1. While logged into NetSuite as an administrator, go to Customization > SuiteBundler > Search & Install Bundles, then search for "Expensify"
-2. Click on the Expensify Connect bundle (Bundle ID 283395)
-3. Click Install
-4. If you already have the Expensify Connect bundle installed, head to _Customization > SuiteBundler > Search & Install Bundles > List_ and update it to the latest version
-5. Select **Show on Existing Custom Forms** for all available fields
-
-## Step 2: Enable Token-Based Authentication
-
-1. Head to _Setup > Company > Enable Features > SuiteCloud > Manage Authentication_
-2. Make sure “Token Based Authentication” is enabled
-3. Click **Save**
-
-## Step 3: Add Expensify Integration Role to a User
-
-The user you select must have access to at least the permissions included in the Expensify Integration Role, but they're not required to be an Admin.
-1. In NetSuite, head to Lists > Employees, and find the user you want to add the Expensify Integration role to
-2. Click _Edit > Access_, then find the Expensify Integration role in the dropdown and add it to the user
-3. Click **Save**
-
-Remember that Tokens are linked to a User and a Role, not solely to a User. It's important to note that you cannot establish a connection with tokens using one role and then switch to another role afterward. Once you've initiated a connection with tokens, you must continue using the same token/user/role combination for all subsequent sync or export actions.
-
-## Step 4: Create Access Tokens
-
-1. Using Global Search in NetSuite, enter “page: tokens”
-2. Click **New Access Token**
-3. Select Expensify as the application (this must be the original Expensify integration from the bundle)
-4. Select the role Expensify Integration
-5. Press **Save**
-6. Copy and Paste the token and token ID to a saved location on your computer (this is the only time you will see these details)
-
-## Step 5: Confirm Expense Reports are Enabled in NetSuite.
-
-Enabling Expense Reports is required as part of Expensify's integration with NetSuite:
-1. Logged into NetSuite as an administrator, go to Setup > Company > Enable Features > Employees
-2. Confirm the checkbox next to Expense Reports is checked
-3. If not, click the checkbox and then Save to enable Expense Reports
-
-## Step 6: Confirm Expense Categories are set up in NetSuite.
-
-Once Expense Reports are enabled, Expense Categories can be set up in NetSuite. Expense Categories are an alias for General Ledger accounts for coding expenses.
-
-1. Logged into NetSuite as an administrator, go to Setup > Accounting > Expense Categories (a list of Expense Categories should show)
-2. If no Expense Categories are visible, click **New** to create new ones
-
-## Step 7: Confirm Journal Entry Transaction Forms are Configured Properly
-
-1. Logged into NetSuite as an administrator, go to _Customization > Forms > Transaction Forms_
-2. Click **Customize** or **Edit** next to the Standard Journal Entry form
-3. Then, click Screen Fields > Main. Please verify the "Created From" label has "Show" checked and the Display Type is set to Normal
-4. Click the sub-header Lines and verify that the "Show" column for "Receipt URL" is checked
-5. Go to _Customization > Forms > Transaction Forms_ and ensure all other transaction forms with the journal type have this same configuration
-
-## Step 8: Confirm Expense Report Transaction Forms are Configured Properly
-
-1. Logged into NetSuite as an administrator, go to _Customization > Forms > Transaction Forms_
-2. Click **Customize** or **Edit** next to the Standard Expense Report form, then click **Screen Fields > Main**
-3. Verify the "Created From" label has "Show" checked and the Display Type is set to Normal
-4. Click the second sub-header, Expenses, and verify that the 'Show' column for 'Receipt URL' is checked
-5. Go to _Customization > Forms > Transaction Forms_ and ensure all other transaction forms with the expense report type have this same configuration
-
-## Step 9: Confirm Vendor Bill Transactions Forms are Configured Properly
-
-1. Logged into NetSuite as an administrator, go to _Customization > Forms > Transaction Forms_
-2. Click **Customize** or **Edit** next to your preferred Vendor Bill form
-3. Then, click _Screen Fields > Main_ and verify that the "Created From" label has "Show" checked and that Departments, Classes, and Locations have the "Show" label unchecked
-4. Under the Expenses sub-header (make sure to click the "Expenses" sub-header at the very bottom and not "Expenses & Items"), ensure "Show" is checked for Receipt URL, Department, Location, and Class
-5. Go to _Customization > Forms > Transaction Forms_ and provide all other transaction forms with the vendor bill type have this same configuration
-
-## Step 10: Confirm Vendor Credit Transactions Forms are Configured Properly
-
-1. While logged in as an administrator, go to _Customization > Forms > Transaction Forms_
-2. Click **Customize** or **Edit** next to your preferred Vendor Credit form, then click _Screen Fields > Main_ and verify that the "Created From" label has "Show" checked and that Departments, Classes, and Locations have the "Show" label unchecked
-3. Under the Expenses sub-header (make sure to click the "Expenses" sub-header at the very bottom and not "Expenses & Items"), ensure "Show" is checked for Receipt URL, Department, Location, and Class
-4. Go to _Customization > Forms > Transaction Forms_ and ensure all other transaction forms with the vendor credit type have this same configuration
-
-## Step 11: Set up Tax Groups (only applicable if tracking taxes)
-
-Expensify imports NetSuite Tax Groups (not Tax Codes), which you can find in NetSuite under _Setup > Accounting > Tax Groups_.
-
-Tax Groups are an alias for Tax Codes in NetSuite and can contain one or more Tax Codes (Please note: for UK and Ireland subsidiaries, please ensure your Tax Groups do not have more than one Tax Code). We recommend naming Tax Groups so your employees can easily understand them, as the name and rate will be displayed in Expensify.
-
-Before importing NetSuite Tax Groups into Expensify:
-1. Create your Tax Groups in NetSuite by going to _Setup > Accounting > Tax Groups_
-2. Click **New**
-3. Select the country for your Tax Group
-4. Enter the Tax Name (this is what employees will see in Expensify)
-5. Select the subsidiary for this Tax Group
-6. Select the Tax Code from the table you wish to include in this Tax Group
-7. Click **Add**
-8. Click **Save**
-9. Create one NetSuite Tax Group for each tax rate you want to show in Expensify
-
-Ensure Tax Groups can be applied to expenses by going to _Setup > Accounting > Set Up Taxes_ and setting the Tax Code Lists Include preference to "Tax Groups And Tax Codes" or "Tax Groups Only."
-
-If this field does not display, it’s not needed for that specific country.
-
-## Step 12: Connect Expensify and NetSuite
-
-1. Log into Expensify as a Policy Admin and go to **Settings > Workspaces > _[Workspace Name]_ > Connections > NetSuite**
-2. Click **Connect to NetSuite**
-3. Enter your Account ID (Account ID can be found in NetSuite by going to _Setup > Integration > Web Services Preferences_)
-4. Then, enter the token and token secret
-5. Click **Connect to NetSuite**
-
-From there, the NetSuite connection will sync, and the configuration dialogue box will appear.
-
-Please note that you must create the connection using a NetSuite account with the Expensify Integration role
-
-Once connected, all reports exported from Expensify will be generated in NetSuite using SOAP Web Services (the term NetSuite employs when records are created through the integration).
-
-# How to Configure Export Settings
-
-There are numerous options for exporting Expensify reports to NetSuite. Let's explore how to configure these settings to align with your business needs.
-To access these settings, head to **Settings > Workspace > Group > Connections** and select the **Configure** button.
-
-## Export Options
-
-### Subsidiary
-
-The subsidiary selection will only appear if you use NetSuite OneWorld and have multiple subsidiaries active. If you add a new subsidiary to NetSuite, sync the workspace connection, and the new subsidiary should appear in the dropdown list under **Settings > Workspaces > _[Workspace Name]_ > Connections**.
-
-### Preferred Exporter
-
-This option allows any admin to export, but the preferred exporter will receive notifications in Expensify regarding the status of exports.
-
-### Date
-
-The three options for the date your report will export with are:
-- Date of last expense: This will use the date of the previous expense on the report
-- Submitted date: The date the employee submitted the report
-- Exported date: The date you export the report to NetSuite
-
-## Reimbursable Expenses
-
-### Expense Reports
-
-Expensify transactions will export reimbursable expenses as expense reports by default, which will be posted to the payables account designated in NetSuite.
-
-### Vendor Bills
-
-Expensify transactions export as vendor bills in NetSuite and will be mapped to the subsidiary associated with the corresponding policy. Each report will be posted as payable to the vendor associated with the employee who submitted the report.
-You can also set an approval level in NetSuite for vendor bills.
-
-### Journal Entries
-
-Expensify transactions that are set to export as journal entries in NetSuite will be mapped to the subsidiary associated with this policy. All the transactions will be posted to the payable account specified in the policy.
-
-You can also set an approval level in NetSuite for the journal entries.
-
-**Important Notes:**
-- Journal entry forms by default do not contain a customer column, so it is not possible to export customers or projects with this export option
-- The credit line and header level classifications are pulled from the employee record
-
-## Non-Reimbursable Expenses
-
-### Vendor Bills
-
-Non-reimbursable expenses will be posted as a vendor bill payable to the default vendor specified in your policy's connection settings. If you centrally manage your company cards through Domains, you can export expenses from each card to a specific vendor in NetSuite. You can also set an approval level in NetSuite for the bills.
-
-### Journal Entries
-
-Non-reimbursable expenses will be posted to the Journal Entries posting account selected in your policy's connection settings. If you centrally manage your company cards through Domains, you can export expenses from each card to a specific account in NetSuite.
-
-**Important Notes:**
-- Expensify Card expenses will always export as Journal Entries, even if you have Expense Reports or Vendor Bills configured for non-reimbursable expenses on the Export tab
-- Journal entry forms do not contain a customer column, so it is not possible to export customers or projects with this export option
-- The credit line and header level classifications are pulled from the employee record
-
-### Expense Reports
-
-To use the expense report option for your corporate card expenses, you will need to set up your default corporate cards in NetSuite.
-
-To use a default corporate card for non-reimbursable expenses, you must select the correct card on the employee records (for individual accounts) or the subsidiary record (If you use a non-one world account, the default is found in your accounting preferences).
-
-Add the corporate card option and corporate card main field to your expense report transaction form in NetSuite by:
-1. Heading to _Customization > Forms > Transaction Forms > Preferred expense report form > Screen Fields_
-2. Under the Main tab, check “Show” for Account for Corporate Card Expenses
-3. On the Expenses tab, check “Show” for Corporate Card
-
-You can select the default account on your employee record to use individual corporate cards for each employee. Make sure you add this field to your employee entity form in NetSuite.
-If you have multiple cards assigned to a single employee, you cannot export to each account. You can only have a single default per employee record.
-
-### Export Invoices
-
-Select the Accounts Receivable account you want your Invoice Reports to export. In NetSuite, the Invoices are linked to the customer, corresponding to the email address where the Invoice was sent.
-
-### Default Vendor Bills
-
-The list of vendors will be available in the dropdown when selecting the option to export non-reimbursable expenses as vendor bills.
-
-# How to Configure Coding Settings
-
-The Coding tab is where NetSuite information is configured in Expensify, which allows employees to code expenses and reports accurately. There are several coding options in NetSuite. Let’s go over each of those below.
-
-## Expense Categories
-
-Expensify's integration with NetSuite automatically imports NetSuite Expense Categories as Categories in Expensify.
-
-Please note that each expense must have a Category selected to export to NetSuite. The category chosen must be imported from NetSuite and cannot be manually created in Expensify.
-
-If you want to delete Categories, you must do this in NetSuite. Categories are added and modified on the integration’s side and then synced with Expensify.
-Once imported, you can turn specific Categories on or off under **Settings > Workspaces > _[Workspace Name]_ > Categories**.
-
-## Tags
-
-The NetSuite integration allows you to configure Customers, Projects, Departments, Classes, and Locations as line-item expense classifications. These are called Tags in Expensify.
-
-Suppose a default Customer, Project, Department, Class, or Location ties to the employee record in NetSuite. In that case, Expensify will create a rule that automatically applies that tag to all expenses made by that employee (the Tag is still editable if necessary).
-
-If you want to delete Tags, you must do this in NetSuite. Tags are added and modified on the integration’s side and then synced with Expensify.
-
-Once imported, you can turn specific Tags on or off under **Settings > Workspaces > _[Workspace Name]_ > Tags**.
-
-## Report Fields
-
-The NetSuite integration allows you to configure Customers, Projects, Departments, Classes, and Locations as report-level classifications. These are called Report Fields in Expensify.
-
-## NetSuite Employee Default
-
-The NetSuite integration allows you to set Departments, Classes, and Locations according to the NetSuite Employee Default for expenses exported as both Expense Reports and Journal Entries.
-
-These fields must be set in NetSuite's employee(s) record(s) to be successfully applied to expenses upon export.
-
-You cannot use the employee default setting with a vendor bill export if you have both a vendor and an employee set up for the user under the same email address and subsidiary.
-
-## Tax
-
-The NetSuite integration allows users to apply a tax rate and amount to each expense. To do this, import Tax Groups from NetSuite:
-1. In NetSuite, head to _Setup > Accounting > Tax Groups_
-2. Once imported, go to the NetSuite connection configuration page in Expensify (under **Settings > Workspaces > Group > _[Workspace Name]_ > Connection > NetSuite > Coding**), refresh the subsidiary list, and the Tax option will appear
-3. From there, enable Tax
-4. Click **Save**
-5. Sync the connection
-6. All Tax Groups for the connected NetSuite subsidiary will be imported to Expensify as taxes.
-7. After syncing, go to **Settings > Workspace > Group > _[Workspace Name]_ > Tax** to see the tax groups imported from NetSuite
-8. Use the turn on/off button to choose which taxes to make available to your employees
-9. Select a default tax to apply to the workspace (that tax rate will automatically apply to all new expenses)
-
-## Custom Segments
-
-To add a Custom Segment to your workspace, you’ll need to locate three fields in NetSuite:
-- Segment Name
-- Internal ID
-- Script/Field ID
-
-**To find the Segment Name:**
-1. Log in as an administrator in NetSuite
-2. Head to _Customization > Lists, Records, & Fields > Custom Segments_
-3. You’ll see the Segment Name on the Custom Segments page
-
-**To find the Internal ID:**
-1. Ensure you have internal IDs enabled in NetSuite under _Home > Set Preferences_
-2. Navigate back to the Custom Segment page
-3. Click the **Custom Record Type** hyperlink
-4. You’ll see the Internal ID on the Custom Record Type page
-
-**To find the Script/Field ID:**
-
-Note that as of 2019.1, any new custom segments that you create automatically use the unified ID, and the Use as Field ID box is not visible. If you are editing a custom segment definition that was created before 2019.1, the Use as Field ID box is available.
-To use a unified ID for the entire custom segment definition, check the Use as Field ID box. When the box is checked, no field ID fields or columns are shown on the Application & Sourcing subtabs because one ID is used for all fields.
-
-- If configuring Custom Segments as Report Fields, use the Field ID on the Transactions tab (under _Custom Segments > Transactions_), or if no Field ID is shown, use the unified ID (just called "ID" right below the "Label").
-- If configuring Custom Segments as Tags, use the Field ID on the Transaction Columns tab (under _Custom Segments > Transaction Columns_), or if no Field ID is shown, use the unified ID (just called "ID" right below the "Label").
-
-Lastly, head over to Expensify and do the following:
-1. Navigate to **Settings > Workspace > Group > _[Workspace Name]_ > Connections > Configure > Coding tab**
-2. Choose how to import Custom Segments (Report Fields or Tags)
-3. Fill out the three fields (Segment Name, Internal ID, Script ID)
-4. Click **Submit**
-
-From there, you should see the values for the Custom Segment under the Tag or Report Field settings in Expensify.
-
-Don’t use the "Filtered by" feature available for Custom Segments. Expensify can’t make these dependent on other fields. If you do have a filter selected, we suggest switching that filter in NetSuite to "Subsidiary" and enabling all subsidiaries to ensure you don't receive any errors upon exporting reports.
-
-### Custom Records
-
-Custom Records are added through the Custom Segments feature.
-
-To add a Custom Record to your workspace, you’ll need to locate three fields in NetSuite:
-- The name of the record
-- Internal ID
-- Transaction Column ID
-
-**To find the Internal ID:**
-1. Make sure you have Internal IDs enabled in NetSuite under Home > Set Preferences
-2. Navigate back to the Custom Segment page
-3. Click the Custom Record Type hyperlink
-4. You’ll see the Internal ID on the Custom Record Type page
-
-**To find the Transaction Column ID:**
-If configuring Custom Segments as Report Fields, use the Field ID on the Transactions tab (under _Custom Segments > Transactions_).
-
-If configuring Custom Segments as Tags, use the Field ID on the Transaction Columns tab (under _Custom Segments > Transaction Columns_).
-
-Lastly, head over to Expensify and do the following:
-1. Navigate to **Settings > Workspace > Group > [Workspace Name]_ > Connections > Configure > Coding tab**
-2. Choose how to import Custom Records (Report Fields or Tags)
-3. Fill out the three fields (the name or label of the record, Internal ID, Transaction Column ID)
-4. Click **Submit**
-
-From there, you should see the values for the Custom Records under the Tag or Report Field settings in Expensify.
-
-### Custom Lists
-
-To add Custom Lists to your workspace, you’ll need to locate two fields in NetSuite:
-- The name of the record
-- The ID of the Transaction Line Field that holds the record
-
-**To find the record:**
-1. Log into Expensify
-2. Head to **Settings > Workspace > Group > _[Workspace Name]_ > Connections > Configure > Coding tab**
-3. The name of the record will be populated in a dropdown list
-
-The name of the record will populate in a dropdown list. If you don't see the one you are looking for, click **Refresh Custom List Options**.
-
-**To find the Transaction Line Field ID:**
-1. Log into NetSuite
-2. Search "Transaction Line Fields" in the global search
-3. Open the option that is holding the record to get the ID
-
-Lastly, head over to Expensify, and do the following:
-1. Navigate to **Settings > Workspaces > Group > _[Workspace Name]_ > Connections > Configure > Coding tab**
-2. Choose how to import Custom Lists (Report Fields or Tags)
-3. Enter the ID in Expensify in the configuration screen
-4. Click **Submit**
-
-From there, you should see the values for the Custom Lists under the Tag or Report Field settings in Expensify.
-
-# How to Configure Advanced Settings
-
-The NetSuite integration’s advanced configuration settings are accessed under **Settings > Workspaces > Group > _[Workspace Name]_ > Connections > NetSuite > Configure > Advanced tab**.
-
-Let’s review the different advanced settings and how they interact with the integration.
-
-## Auto Sync
-
-Enabling Auto Sync ensures that the information in NetSuite and Expensify is always in sync through automating exports, tracking direct deposits, and communicating export errors.
-
-**Automatic Export:**
-- When you turn on the Auto Sync feature in Expensify, any final report you approve will automatically be sent to NetSuite.
-- This happens every day at approximately the same time.
-
-**Direct Deposit Alert:**
-- If you use Expensify's Direct Deposit ACH and have Auto Sync, getting reimbursed for an Expensify report will automatically create a Bill Payment in NetSuite.
-
-**Tracking Exports and Errors:**
-- In the comments section of an Expensify report, you can find extra details about the report.
-- The comments section will tell you when the report was sent to NetSuite, and if there were any problems during the export, it will show the error.
-
-## Newly Imported Categories
-
-With this enabled, all submitters can add any newly imported Categories to an Expense.
-
-## Invite Employees & Set Approval Workflow
-
-### Invite Employees
-
-Use this option in Expensify to bring your employees from a specific NetSuite subsidiary into Expensify.
-Once imported, Expensify will send them an email letting them know they've been added to a workspace.
-
-### Set Approval Workflow
-
-Besides inviting employees, you can also establish an approval process in NetSuite.
-
-By doing this, the Approval Workflow in Expensify will automatically follow the same rules as NetSuite, typically starting with Manager Approval.
-
-- **Basic Approval:** A single level of approval, where all users submit directly to a Final Approver. The Final Approver defaults to the workspace owner but can be edited on the people page.
-- **Manager Approval (default):** Two levels of approval route reports first to an employee's NetSuite expense approver or supervisor, and second to a workspace-wide Final Approver. By NetSuite convention, Expensify will map to the supervisor if no expense approver exists. The Final Approver defaults to the workspace owner but can be edited on the people page.
-- **Configure Manually:** Employees will be imported, but all levels of approval must be manually configured on the workspace's People settings page. If you enable this setting, it’s recommended you review the newly imported employees and managers on the **Settings > Workspaces > Group > _[Workspace Name]_ > People page**. You can set a user role for each new employee and enforce an approval workflow.
-
-## Automatically Create Employees/Vendors
-
-With this feature enabled, Expensify will automatically create a new employee or vendor (if one doesn’t already exist) from the email of the report submitter in NetSuite.
-
-## Export Foreign Currency Amount
-
-Using this feature allows you to send the original amount of the expense rather than the converted total when exporting to NetSuite. This option is available if you are exporting reimbursable expenses as Expense Reports.
-
-## Cross-Subsidiary Customers/Projects
-
-This allows you to import Customers and Projects across all subsidiaries to a single group workspace. For this functionality, you must enable "Intercompany Time and Expense" in NetSuite.
-
-That feature is found in NetSuite under _Setup > Company > Setup Tasks: Enable Features > Advanced Features_.
-
-## Sync Reimbursed Reports
-
-If you're using Expensify's Direct Deposit ACH feature and you want to export reimbursable expenses as either Expense Reports or Vendor Bills in NetSuite, here's what to do:
-1. In Expensify, go to the Advanced Settings tab
-2. Look for a toggle or switch related to this feature
-3. Turn it on by clicking the toggle
-4. Select the correct account for the Bill Payment in NetSuite
-5. Ensure the account you choose matches the default account for Bill Payments in NetSuite
-
-That's it! When Expensify reimburses an expense report, it will automatically create a corresponding Bill Payment in NetSuite.
-
-Alternatively, if reimbursing outside of Expensify, this feature will automatically update the expense report status in Expensify from Approved to Reimbursed when the respective report is paid in NetSuite and the corresponding workspace syncs via Auto-Sync or when the integration connection is manually synced.
-
-## Setting Approval Levels
-
-With this setting enabled, you can set approval levels based on your export type.
-
-- **Expense Reports:** These options correspond to the default preferences in NetSuite – “Supervisor approval only,” “Accounting approval only,” or “Supervisor and Accounting approved.”
-- **Vendor Bills or Journal Entries:** These options correspond to the default preferences in NetSuite – “Pending Approval” or “Approved for Posting.”
-
-If you have Approval Routing selected in your accounting preference, this will override the selections in Expensify.
-
-If you do not wish to use Approval Routing in NetSuite, go to _Setup > Accounting > Accounting Preferences > Approval Routing_ and ensure Vendor Bills and Journal Entries are not selected.
-
-### Collection Account
-
-When exporting invoices, once marked as Paid, the payment is marked against the account selected after enabling the Collection Account setting.
-
-# Deep Dive
-
-## Categories
-
-You can use the Auto-Categorization feature so that expenses are automatically categorized.
-
-To set Category Rules (e.g., receipt requirements or comments), go to the categories page in the workspace under **Settings > Workspaces > _[Workspace Name]_ > Categories**.
-
-With this setting enabled, when an Expense Category updates in NetSuite, it will update in Expensify automatically.
-
-## Company Cards
-
-NetSuite's company card feature simplifies exporting reimbursable and non-reimbursable transactions to your General Ledger (GL). This approach is recommended for several reasons:
-
-1. **Separate Employees from Vendors:** NetSuite allows you to maintain separate employee and vendor records. This feature proves especially valuable when integrating with Expensify. By utilizing employee defaults for classifications, your employees won't need to apply tags to all their expenses manually.
-2. **Default Accounts Payable (A/P) Account:** Expense reports enable you to set a default A/P account for export on your subsidiary record. Unlike vendor bills, where the A/P account defaults to the last selected account, the expense report export option allows you to establish a default A/P account.
-3. **Mix Reimbursable and Non-Reimbursable Expenses:** You can freely mix reimbursable and non-reimbursable expenses without categorizing them in NetSuite after export. NetSuite's corporate card feature automatically categorizes expenses into the correct GL accounts, ensuring a neat and organized GL impact.
-
-#### Let’s go over an example!
-
-Consider an expense report with one reimbursable and one non-reimbursable expense. Each needs to be exported to different accounts and expense categories.
-
-In NetSuite, you can quickly identify the non-reimbursable expense marked as a corporate card expense. Reviewing the GL impact, you'll notice that the reimbursable expense is posted to the default A/P account set on the subsidiary record. On the other hand, the company card expense is assigned to the Credit Card account, which can either be set as a default on the subsidiary record (for a single account) or the employee record (for individual credit card accounts in NetSuite).
-
-Furthermore, each expense is categorized according to your selected expense category.
-
-You'll need to set up default corporate cards in NetSuite to use the expense report option for your corporate card expenses.
-
-For non-reimbursable expenses, choose the appropriate card on the subsidiary record. You can find the default in your accounting preferences if you're not using a OneWorld account.
-
-Add the corporate card option and the corporate card main field to configure your expense report transaction form in NetSuite:
-1. Go to _Customization > Forms > Transaction Forms > Preferred expense report form > Screen Fields_
-2. Under the Main tab, check "Show for Account for Corporate Card Expenses"
-3. On the Expenses tab, check "Show for Corporate Card"
-
-If you prefer individual corporate cards for each employee, you can select the default account on the employee record. Add this field to your employee entity form in NetSuite (under _Customize > Customize Form_ from any employee record). Note that each employee can have only one corporate card account default.
-
-### Exporting Company Cards to GL Accounts in NetSuite
-
-If you need to export company card transactions to individual GL accounts, you can set that up at the domain level.
-
-Let’s go over how to do that:
-1. Go to **Settings > Domain > _[Domain name]_ > Company Cards**
-2. Click the Export Settings cog on the right-hand side of the card and select the GL account where you want the expenses to export
-
-After setting the account, exported expenses will be mapped to that designated account.
-
-## Tax
-
-You’ll want to set up Tax Groups in Expensify if you're keeping track of taxes.
-
-Expensify can import "NetSuite Tax Groups" (not Tax Codes) from NetSuite. Tax Groups can contain one or more Tax Codes. If you have subsidiaries in the UK or Ireland, ensure your Tax Groups have only one Tax Code.
-
-You can locate these in NetSuite by setting up> Accounting > Tax Groups.
-
-You’ll want to name Tax Groups something that makes sense to your employees since both the name and the tax rate will appear in Expensify.
-
-To bring NetSuite Tax Groups into Expensify, here's what you need to do:
-1. Create your Tax Groups in NetSuite by going to _Setup > Accounting > Tax Groups_
-2. Click **New**
-3. Pick the country for your Tax Group
-4. Enter the Tax Name (this will be visible to your employees in Expensify)
-5. Next, select the subsidiary for this Tax Group
-6. Finally, from the table, choose the Tax Code you want to include in this Tax Group
-7. Click **Add**, then click **Save**
-
-Repeat those steps for each tax rate you want to use in Expensify.
-
-Next, ensure that Tax Groups can be applied to expenses:
-1. In NetSuite, head to _Setup > Accounting > Set Up Taxes_
-2. Set the preference for "Tax Code Lists Include" to either "Tax Groups And Tax Codes" or "Tax Groups Only." If you don't see this field, don't worry; it means you don't need to set it for that specific country
-
-NetSuite has a pre-made list of tax groups for specific locations, but you can also create your own. We'll import both your custom tax groups and the default ones. It's important not to deactivate the default NetSuite tax groups because we rely on them for exporting specific types of expenses.
-
-For example, there's a default Canadian tax group called CA-Zero, which we use when exporting mileage and per diem expenses that don't have any taxes applied in
-
-Expensify. If you deactivate this group in NetSuite, it will lead to export errors.
-
-Additionally, some tax nexuses in NetSuite have specific settings that need to be configured in a certain way to work seamlessly with the Expensify integration:
-- In the Tax Code Lists Include field, choose "Tax Groups" or "Tax Groups and Tax Codes." This setting determines how tax information is handled.
-- In the Tax Rounding Method field, select "Round Off." Although it won't cause connection errors, not using this setting can result in exported amounts differing from what NetSuite expects.
-
-If your tax groups are importing into Expensify but not exporting to NetSuite, check that each tax group has the right subsidiaries enabled. That is crucial for proper data exchange.
-
-## Multi-Currency
-
-When using multi-currency features with NetSuite, remember these points:
-
-**Matching Currencies:** The currency set for a vendor or employee record must match the currency chosen for the subsidiary in your Expensify configuration. This alignment is crucial for proper handling.
-
-**Foreign Currency Conversion:** If you create expenses in one currency and then convert them to another currency within Expensify before exporting, you can include both the original and converted amounts in the exported expense reports. This option, called "Export foreign currency amount," can be found in the Advanced tab of your configuration. Note that Expensify sends only the amounts; the actual currency conversion is performed in NetSuite.
-
-**Bank Account Currency:** When synchronizing bill payments, make sure your bank account's currency matches the subsidiary's currency. Failure to do so will result in an "Invalid Account" error. This alignment is necessary to prevent issues during payment processing.
-
-## Exporting Invoices
-
-When you mark an invoice as paid in Expensify, the paid status syncs with NetSuite and vice versa!
-
-Let's dive right in:
-1. Access Configuration Settings: Go to **Settings > Workspace > Group > _[Workspace Name]_ > Connections > Configuration**
-2. Choose Your Accounts Receivable Account: Scroll down to "Export Expenses to" and select the appropriate Accounts Receivable account from the dropdown list. If you don't see any options, try syncing your NetSuite connection by returning to the Connections page and clicking **Sync Now**
-
-### Exporting an Invoice to NetSuite
-
-Invoices will be automatically sent to NetSuite when they are in the "Processing" or "Paid" status. This ensures you always have an up-to-date record of unpaid and paid invoices.
-
-If you have Auto Sync disabled, you'll need to export your invoices, along with your expense reports, manually. Follow these three simple steps:
-1. Filter Invoices: From your Reports page, use filters to find the invoices you want to export.
-2. Select Invoices: Pick the invoices ready for export.
-3. Export to NetSuite: Click **Export to NetSuite** in the top right-hand corner.
-
-When exporting to NetSuite, we match the recipient's email address on the invoice to a customer record in NetSuite, meaning each customer in NetSuite must have an email address in their profile. If we can't find a match, we'll create a new customer in NetSuite.
-
-Once exported, the invoice will appear in the Accounts Receivable account you selected during your NetSuite Export configuration.
-
-### Updating an Invoice to paid
-
-When you mark an invoice as "Paid" in Expensify, this status will automatically update in NetSuite. Similarly, if the invoice is marked as "Paid" in NetSuite, it will sync with Expensify. The payment will be reflected in the Collection account specified in your Advanced Settings Configuration.
-
-## Download NetSuite Logs
-
-Sometimes, we might need more details from you to troubleshoot issues with your NetSuite connection. Providing the NetSuite web services usage logs is incredibly useful.
-
-Here's how you can send them to us:
-1. **Generate the Logs:** Start by trying to export a report from your system. This action will create the most recent logs that we require.
-2. **Access Web Services Usage Logs:** You can locate these logs in your NetSuite account. Just use the global search bar at the top of the page and type in "Web Services Usage Log."
-3. **Identify the Logs:** Look for the most recent log entry. It should have "FAILED" under the STATUS column. Click on the two blue "view" links under the REQUEST and RESPONSE columns. These are the two .xml files we need to examine.
-
-Send these two files to your Account Manager or Concierge so we can continue troubleshooting!
-
-{% include faq-begin.md %}
-
-## What type of Expensify plan is required for connecting to NetSuite?
-
-You need a group workspace on a Control Plan to integrate with NetSuite.
-
-## How does Auto Sync work with reimbursed reports?
-
-If a report is reimbursed via ACH or marked as reimbursed in Expensify and then exported to NetSuite, the report is automatically marked as paid in NetSuite during the next sync.
-
-If a report is exported to NetSuite and then marked as paid in NetSuite, the report is automatically marked as reimbursed in Expensify during the next sync.
-
-## If I enable Auto Sync, what happens to existing approved and reimbursed reports?
-
-If you previously had Auto Sync disabled but want to allow that feature to be used going forward, you can safely turn on Auto Sync without affecting existing reports. Auto Sync will only take effect for reports created after enabling that feature.
-
-{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspaces/Configure-Reimbursement-Settings.md b/docs/articles/expensify-classic/workspaces/Configure-Reimbursement-Settings.md
new file mode 100644
index 000000000000..aea84d338934
--- /dev/null
+++ b/docs/articles/expensify-classic/workspaces/Configure-Reimbursement-Settings.md
@@ -0,0 +1,55 @@
+---
+title: Configure Reimbursement Settings
+description: Set up direct or indirect reimbursements for your workspace.
+---
+
+
+Reimbursing employees in Expensify is quick, easy, and completely free. Let Expensify do the tedious work for you by taking advantage of the features available to automate employee reimbursement.
+
+# Configure a Workspace's Reimbursement Settings
+There are a few ways to reimburse employees in Expensify. The option that's best suited for you and your business will depend on a few different factors:
+- **Direct Reimbursement**: For companies with a business bank account located in the US that reimburse employees within the US.
+- **Indirect Reimbursement**: This option is available to all members, and connecting a bank account to Expensify is not required. Indirect reimbursement indicates that all reports are reimbursed outside of Expensify.
+- **Global Reimbursement**: If your company’s business bank account is in the US, Canada, the UK, Europe, or Australia, you can reimburse employees directly in nearly any country worldwide.
+
+## Set Up Direct Reimbursement
+
+Once a [business bank account is connected to Expensify](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Business-Bank-Accounts-USD#how-to-add-a-verified-business-bank-account), a workspace admin can enable indirect reimbursement via **Settings > Workspaces > Workspace Name > Reimbursement > Direct**.
+
+#### Additional features available with Direct Reimbursement:
+- **Select a default reimburser for the Workspace from the dropdown menu**:
+ - The default reimburser will receive notifications to reimburse reports in Expensify.
+ - Any workspace admin who also has access to the business bank account can be added as a default reimburser.
+- **Set a default withdrawal account for the Workspace**:
+ - The default bank account is used to reimburse all of the reports submitted on the corresponding workspace.
+- **Set a manual reimbursement threshold to automate reimbursement**:
+ - If the total of a given report is less than the threshold set, reimbursement will occur automatically upon final approval.
+ - If the total of a given report is more than the threshold, it will need to be reimbursed manually.
+
+## Set Up Indirect Reimbursement
+
+A Workspace admin can enable indirect reimbursement via **Settings > Workspaces > Workspace Name > Reimbursement > Indirect**.
+
+**Additional features under Reimbursement > Indirect:**
+If you reimburse through a separate system or through payroll, Expensify can collect and export employee bank account details for you. Reach out to your Account Manager or Concierge to have the Reimbursement Details Export format added to the account.
+
+## Set Up Global Reimbursement
+
+Once [a business bank account is connected to Expensify](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Business-Bank-Accounts-USD#how-to-add-a-verified-business-bank-account), a workspace admin can enable indirect reimbursement via **Settings > Workspaces > Workspace Name > Reimbursement > Direct > Enable Global Reimbursements**.
+
+More information on setting up global reimbursements can be found **[here](https://help.expensify.com/articles/expensify-classic/bank-accounts-and-payments/Global-Reimbursements)**.
+
+{% include faq-begin.md %}
+
+## How do I export employee bank account details once the Reimbursement Details Export format is added to my account?
+
+Employee bank account details can be exported from the Reports page by selecting the relevant Approved reports and then clicking **Export to > Reimbursement Details Export**.
+
+## Is it possible to change the name of a verified business bank account in Expensify?
+
+Bank account names can be updated by going to _**Settings > Accounts > Payments**_ and clicking the pencil icon next to the bank account name.
+
+## What is the benefit of setting a default reimburser?
+
+Setting a default reimburser on the Workspace ensures that all outstanding reports are reimbursed as this member will receive notifications alerting them to reports that require their action.
+{% include faq-end.md %}
diff --git a/docs/articles/expensify-classic/workspaces/Expenses.md b/docs/articles/expensify-classic/workspaces/Expense-Settings.md
similarity index 61%
rename from docs/articles/expensify-classic/workspaces/Expenses.md
rename to docs/articles/expensify-classic/workspaces/Expense-Settings.md
index 4a2dc56c430f..c3a8ab31394d 100644
--- a/docs/articles/expensify-classic/workspaces/Expenses.md
+++ b/docs/articles/expensify-classic/workspaces/Expense-Settings.md
@@ -2,19 +2,29 @@
title: Expensify Workspace Expense Settings
description: Expense Settings
---
-# Overview
+Expensify offers multiple ways to customize how expenses are created and managed at the workspace level. Whether you’re using an individual workspace or managing expenses in a group workspace, there are various expense settings you can customize.
-Expensify offers multiple ways to customize how expenses are created in your workspace. In this doc, you’ll learn how to set up expense basics, distance expenses, and time expenses.
+# Set up the expense settings on a workspace
-Whether you’re flying solo with your Individual workspace or submitting with a team on your Group workspace, we have settings to support how you use Expensify.
+You can manage the expense settings on a workspace under **Settings** > **Workspaces** > **Individual** or **Group** > [_Workspace Name_] > **Expenses**. From here you can customize the following expense-level settings:
+- **Violations**: When enabled, employee expenses that fall outside of workspace preferences are flagged as violations.
+- **Preferences**: Configure the reimbursable and billable settings for the expenses submitted to the corresponding workspace.
+- **Distance**: This is where you can set the reimbursable mileage rates for yourself or your employees.
+- **Time**: Set an hourly billable rate so members of the workspace can create time expenses for reimbursement.
-# How to manage expense settings in your workspace
+## Violations
+A workspace admin can customize the following parameters at the expense level:
+- **Max Expense Age (Days)**
+- **Max Expense Amount**
+- **Receipt Required Amount**
-Let’s cover the expense basics first! In the following sections, we’ll go through each part of managing expense settings in your workspace.
+If an expense is submitted that falls outside of those parameters, Expensify will automatically detect it as a violation and alert both the expense creator and reviewer that it needs to be corrected.
-## Controlling cash expenses
+More information on violations can be found [**here**](https://help.expensify.com/articles/expensify-classic/workspaces/Enable-and-set-up-expense-violations).
-A cash expense is any expense created manually or by uploading a receipt for SmartScan; a cash expense does not mean the expense was paid for with cash. The other type of expense you’ll most commonly see is credit card expenses, which means the expenses imported from a credit card or bank connection.
+## Preferences
+
+A cash expense is any expense created manually or by uploading a receipt for SmartScan; it does not mean the expense was paid for with cash. The other type of expense you’ll most commonly see is credit card expenses, which are expenses imported from a credit card or bank connection.
There are four options for cash expenses:
@@ -23,7 +33,7 @@ There are four options for cash expenses:
- **Forced always reimbursable** - All cash expenses are forced to be reimbursable; they cannot be marked as non-reimbursable.
- **Forced always non-reimbursable** - All cash expenses are forced to be non-reimbursable; they cannot be marked as reimbursable.
-## Setting up billable expenses
+### Billable expenses
Billable expenses refer to expenses you or your employees incur that need to be re-billed to a specific client or vendor.
@@ -37,7 +47,7 @@ Under Expense Basics, you can choose the setting that is best for you.
If your Group workspace is connected to Xero, QuickBooks Online, NetSuite, or Sage Intacct, you can export billable expenses to be invoiced to customers. To set this up, go to the Coding tab in the connection configuration settings.
-## Using eReceipts
+### eReceipts
eReceipts are full digital replacements of their paper equivalents for purchases of $75 or less.
@@ -46,65 +56,57 @@ Click the toggle to your preferred configuration.
- **Enabled** - All imported credit card expenses in US dollars of $75 or less will have eReceipts in the receipt image.
- **Disabled** - No expenses will generate an eReceipt.
-Note: _We will not generate an eReceipt for lodging expenses._
+Note: Expensify will not generate an eReceipt for lodging expenses.
-## Securing receipt images
+### Secure receipt images
Whether you’re sharing your receipts with your accountant, having an auditor review exported expenses, or simply wanting to export to keep a hard copy for yourself, receipt visibility will be an essential consideration.
Under _Public Receipt Visibility_, you can determine who can view receipts on your workspace.
- **Enabled** means receipts are viewable by anyone with the URL. They don't need to be an Expensify user or a workspace member to view receipts.
-- **Disabled** means receipts are viewable by users of Expensify, who would have access to view the receipt in the application. You must be an Expensify user with access to the report a receipt is on and logged into your account to view a receipt image via URL.
+- **Disabled** means receipts are viewable by Expensify users, who would have access to view the receipt in the application. You must be an Expensify user with access to the report a receipt is on and logged into your account to view a receipt image via URL.
-## Track mileage expenses
+## Distance Expenses
+How to set up distance expenses:
+1. Select whether you want to capture _miles_ or _kilometers_,
+2. Set the default category to be used on distance expenses,
+3. Click **Add A Mileage Rate** to add as many rates as you need,
+4. Set the reimbursable amount per mile or kilometer.
-Whether using the Individual or Group workspace, you can create distance rates to capture expenses in miles or kilometers.
+**Note:** If a rate is toggled off it is immediately disabled. This means that users are no longer able to select it when creating a new distance expense. If only one rate is available then that rate will be toggled on by default.
-Preliminary setup steps include:
+### Track tax on mileage expenses
+If you’re tracking tax in Expensify you can also track tax on distance expenses. The first step is to enable tax in the workspace. You can do this by going to **Settings** > **Workspaces** > **Individual** or **Group** > [_Workspace Name_] > **Tax**.
-1. Selecting whether you want to capture _miles_ or _kilometers_,
-2. Setting the default category to be used on distance expenses,
-3. Click **Add A Mileage Rate** to add as many rates as you need,
-4. Set the reimbursable amount per mile or kilometer.
+Once tax is enabled on a workspace level you will see a toggle to _Track Tax_ in the Distance section of the workspace settings. If tax is disabled on the workspace the Track Tax toggle will not display.
-Note: _If a rate is toggled off it is immediately disabled. This means that users are no longer able to select it when creating a new distance expense. If only one rate is available then that rate will be toggled on by default._
+When Track Tax is enabled, you will need to enter additional information about the rates you have set. This includes the _Tax Reclaimable on_ and _Tax Rate_ fields. With that information, Expensify will work out the correct tax reclaim for each expense.
-## Set an hourly rate
+If you enable tax but don’t select a tax rate or enter a tax reclaimable amount, we will not calculate any tax amount for that rate. If, at any point, you switch the tax rate or enter a different reclaimable portion for an existing distance rate, the mileage rate will need to be re-selected on expenses for the tax amount to update according to the new values.
-Using Expensify you can track time-based expenses to bill your clients at an hourly rate or allow employees to claim an hourly stipend.
+**Note:** Expensify won’t automatically track cumulative mileage. If you need to track cumulative mileage per employee, we recommend building a mileage report using our custom export formulas.
-Click the toggle under the _Time_ section to enable the feature and set a default hourly rate. After that, you and your users will be able to create time-based expenses from the [**Expenses**](https://expensify.com/expenses) page of the account.
+## Time Expenses
-# Deep dives
+Using Expensify you can track time-based expenses to bill your clients at an hourly rate or allow employees to claim an hourly stipend.
-## What is Concierge Receipt Audit for the Control Plan?
+Click the toggle under the _Time_ section to enable the feature and set a default hourly rate. Then, you and your users can create time-based expenses from the [**Expenses**](https://expensify.com/expenses) page of the account.
-Concierge Receipt Audit is a real-time audit and compliance of receipts submitted by employees and workspace users. Concierge checks every receipt for accuracy and compliance, flagging any expenses that seem fishy before expense reports are even submitted for approval. All risky expenses are highlighted for manual review, leaving you with more control over and visibility into expenses. When a report is submitted and there are risky expenses on it, you will be immediately prompted to review the risky expenses and determine the next steps.
+## Concierge Receipt Audit
-**Why you should use Concierge Receipt Audit**
+Concierge Receipt Audit is a real-time audit and compliance of receipts submitted by employees and workspace users. Concierge checks every receipt for accuracy and compliance, flagging any expenses that seem fishy before expense reports are even submitted for approval. All risky expenses are highlighted for manual review, leaving you with more control over and visibility into expenses. When a report is submitted and there are risky expenses on it, you will be immediately prompted to review the risky expenses and determine the next steps.
+**Benefits of Concierge Receipt Audit**
- To make sure you don't miss any risky expenses that need human oversight.
- To avoid needing to manually review all your company receipts.
- It's included at no extra cost with the [Control Plan](https://www.expensify.com/pricing).
- Instead of paying someone to audit your company expenses or being concerned that your expenses might be audited by a government agency.
-- It's easy to use! Concierge will alert you to the risky expense and present it to you in an easy-to-follow review tutorial.
+- It's easy -- Concierge will alert you to the risky expense and present it to you in an easy-to-follow review tutorial.
- In addition to the risky expense alerts, Expensify will include a Note with audit details on every report.
-Note: _If a report has audit alerts on it, you'll need to Review the report and Accept the alerts before it can be approved._
-
-## Tracking tax on mileage expenses
-
-If you’re tracking tax in Expensify you can also track tax on distance expenses. The first step is to enable tax in the workspace. You can do this by going to **Settings** > **Workspaces** > **Individual** or **Group** > [_Workspace Name_] > **Tax**.
-
-Once tax is enabled on a workspace level you will see a toggle to _Track Tax_ in the Distance section of the workspace settings. If tax is disabled on the workspace the Track Tax toggle will not display.
-
-When Track Tax is enabled you will need to enter additional information to the rates you have set, this includes the _Tax Reclaimable on_ and _Tax Rate_ fields. With that information, Expensify will work out the correct tax reclaim for each expense.
-
-If you enable tax but don’t select a tax rate or enter a tax reclaimable amount, we will not calculate any tax amount for that rate. If, at any point, you switch the tax rate or enter a different reclaimable portion for an existing distance rate, the mileage rate will need to be re-selected on expenses for the tax amount to update according to the new values.
-
-Note: _Expensify won’t automatically track cumulative mileage. If you need to track cumulative mileage per employee, we recommend building a mileage report using our custom export formulas._
+**Note:** If a report has audit alerts on it, you'll need to Review the report and Accept the alerts before it can be approved.
{% include faq-begin.md %}
diff --git a/docs/articles/expensify-classic/workspaces/Reimbursement.md b/docs/articles/expensify-classic/workspaces/Reimbursement.md
deleted file mode 100644
index ed2384d12006..000000000000
--- a/docs/articles/expensify-classic/workspaces/Reimbursement.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: Reimbursement
-description: Enable reimbursement and reimburse expense reports
----
-
-
-# Overview
-Reimbursement in Expensify is quick, easy, and completely free. Let Expensify do the tedious work for you by taking advantage of features to automate employee reimbursement.
-
-# How to Enable Reimbursement
-There are several options for reimbursing employees in Expensify. The options available will depend on which country your business bank account is domiciled in.
-
-## Direct Reimbursement
-
-Direct reimbursement is available to companies who have a verified US bank account and are reimbursing employees within the US. To use direct reimbursement, you must have a US business bank account verified in Expensify.
-
-A Workspace admin can enable direct reimbursement via **Settings > Workspaces > Workspace Name > Reimbursement > Direct**.
-
-**Additional features under Reimbursement > Direct:**
- - Select a **default reimburser** for the Workspace from the dropdown menu. The default reimburser is the person who will receive notifications to reimburse reports in Expensify. You’ll be able to choose among all Workspace Admins who have access to the business bank account.
- - Set a **default withdrawal account** for the Workspace. This will set a default bank account that report reimbursements are withdrawn from.
- - Set a **manual reimbursement threshold** to automate reimbursement. Reports whose total falls under the manual reimbursement threshhold will be reimbursed automatocally upon final approval; reports whose total falls above the threshhold will need to be reimbursed manually by the default reimburser.
-
-Expensify also offers direct global reimbursement to some companies with verified bank accounts in USD, GBP, EUR and AUD who are reimbursing employees internationally. For more information about Global Reimbursement, see LINK
-
-## Indirect Reimbursement
-
-Indirect reimbursement is available to all companies in Expensify and no bank account is required. Indirect reimbursement indicates that the report will be reimbursed outside of Expensify.
-
-A Workspace admin can enanble indirect reimbursement via **Settings > Workspaces > Workspace Name > Reimbursement > Indirect**.
-
-**Additional features under Reimbursement > Indirect:**
-If you reimburse through a seperate system or through payroll, Expensify can collect and export employee bank account details for you. Just reach out to your Account Manager or concierge@expensify.com for us to add the Reimbursement Details Export format to the account.
-
-{% include faq-begin.md %}
-
-## How do I export employee bank account details once the Reimbursement Details Export format is added to my account?
-
-Employee bank account details can be exported from the Reports page by selecting the relevant Approved reports and then clicking **Export to > Reimbursement Details Export**.
-
-## Is it possible to change the name of a verified business bank account in Expensify?
-
-Bank account names can be updated via **Settings > Accounts > Payments** and clicking the pencil icon next to the bank account name.
-
-## What is the benefit of setting a default reimburser?
-
-The main benefit of being defined as the "reimburser" in the Workspace settings is that this user will receive notifications on their Home page alerting them when reports need to be reimbursed.
-{% include faq-end.md %}
diff --git a/docs/articles/new-expensify/connections/Set-up-QuickBooks-Online-connection.md b/docs/articles/new-expensify/connections/Set-up-QuickBooks-Online-connection.md
index 155512866a8f..79d5b17055f7 100644
--- a/docs/articles/new-expensify/connections/Set-up-QuickBooks-Online-connection.md
+++ b/docs/articles/new-expensify/connections/Set-up-QuickBooks-Online-connection.md
@@ -52,6 +52,12 @@ Log in to QuickBooks Online and ensure all of your employees are setup as either
![The QuickBooks Online Connect button]({{site.url}}/assets/images/ExpensifyHelp-QBO-3.png){:width="100%"}
+![The QuickBooks Online Connect Accounting button]({{site.url}}/assets/images/ExpensifyHelp-QBO-4.png){:width="100%"}
+
+![The QuickBooks Online Connect Connect button]({{site.url}}/assets/images/ExpensifyHelp-QBO-5.png){:width="100%"}
+
+
+
# Step 3: Configure import settings
The following steps help you determine how data will be imported from QuickBooks Online to Expensify.
diff --git a/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md b/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md
index 588f0da20154..6546f57073ee 100644
--- a/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md
+++ b/docs/articles/new-expensify/expenses-&-payments/Send-an-invoice.md
@@ -38,6 +38,9 @@ Once an invoice is sent, the customer receives an automated email or text messag
4. Click **Pay Elsewhere**, which will mark the invoice as Paid.
Currently, invoices must be paid outside of Expensify. However, the ability to make payments through Expensify is coming soon.
+
+![A photo of the pay button]({{site.url}}/assets/images/ExpensifyHelp-Invoice-1.png){:width="100%"}
+
# FAQs
diff --git a/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_01.png b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_01.png
new file mode 100644
index 000000000000..8d8222bc76b5
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_01.png differ
diff --git a/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_02.png b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_02.png
new file mode 100644
index 000000000000..7fb0afc5d8ff
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_02.png differ
diff --git a/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_03.png b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_03.png
new file mode 100644
index 000000000000..68a1f3e65be6
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_03.png differ
diff --git a/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_04.png b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_04.png
new file mode 100644
index 000000000000..c62146e2ed43
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_04.png differ
diff --git a/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_05.png b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_05.png
new file mode 100644
index 000000000000..d3cfafa4e6a7
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_05.png differ
diff --git a/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_06.png b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_06.png
new file mode 100644
index 000000000000..347551a85c59
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_06.png differ
diff --git a/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_07.png b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_07.png
new file mode 100644
index 000000000000..83071f380e6e
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp-WorkspaceFeeds_07.png differ
diff --git a/docs/expensify-classic/hubs/connect-credit-cards/business-bank-accounts.html b/docs/expensify-classic/hubs/bank-accounts-and-payments/payments.html
similarity index 100%
rename from docs/expensify-classic/hubs/connect-credit-cards/business-bank-accounts.html
rename to docs/expensify-classic/hubs/bank-accounts-and-payments/payments.html
diff --git a/docs/expensify-classic/hubs/connect-credit-cards/deposit-accounts.html b/docs/expensify-classic/hubs/connections/accelo.html
similarity index 100%
rename from docs/expensify-classic/hubs/connect-credit-cards/deposit-accounts.html
rename to docs/expensify-classic/hubs/connections/accelo.html
diff --git a/docs/expensify-classic/hubs/expenses/expenses.html b/docs/expensify-classic/hubs/connections/certinia.html
similarity index 100%
rename from docs/expensify-classic/hubs/expenses/expenses.html
rename to docs/expensify-classic/hubs/connections/certinia.html
diff --git a/docs/expensify-classic/hubs/integrations/index.html b/docs/expensify-classic/hubs/connections/index.html
similarity index 100%
rename from docs/expensify-classic/hubs/integrations/index.html
rename to docs/expensify-classic/hubs/connections/index.html
diff --git a/docs/expensify-classic/hubs/expenses/reports.html b/docs/expensify-classic/hubs/connections/netsuite.html
similarity index 100%
rename from docs/expensify-classic/hubs/expenses/reports.html
rename to docs/expensify-classic/hubs/connections/netsuite.html
diff --git a/docs/expensify-classic/hubs/getting-started/approved-accountants.html b/docs/expensify-classic/hubs/connections/quickbooks-desktop.html
similarity index 100%
rename from docs/expensify-classic/hubs/getting-started/approved-accountants.html
rename to docs/expensify-classic/hubs/connections/quickbooks-desktop.html
diff --git a/docs/expensify-classic/hubs/getting-started/support.html b/docs/expensify-classic/hubs/connections/quickbooks-online.html
similarity index 100%
rename from docs/expensify-classic/hubs/getting-started/support.html
rename to docs/expensify-classic/hubs/connections/quickbooks-online.html
diff --git a/docs/expensify-classic/hubs/getting-started/tips-and-tricks.html b/docs/expensify-classic/hubs/connections/sage-intacct.html
similarity index 100%
rename from docs/expensify-classic/hubs/getting-started/tips-and-tricks.html
rename to docs/expensify-classic/hubs/connections/sage-intacct.html
diff --git a/docs/expensify-classic/hubs/integrations/HR-integrations.html b/docs/expensify-classic/hubs/connections/xero.html
similarity index 100%
rename from docs/expensify-classic/hubs/integrations/HR-integrations.html
rename to docs/expensify-classic/hubs/connections/xero.html
diff --git a/docs/expensify-classic/hubs/integrations/accounting-integrations.html b/docs/expensify-classic/hubs/integrations/accounting-integrations.html
deleted file mode 100644
index 86641ee60b7d..000000000000
--- a/docs/expensify-classic/hubs/integrations/accounting-integrations.html
+++ /dev/null
@@ -1,5 +0,0 @@
----
-layout: default
----
-
-{% include section.html %}
diff --git a/docs/expensify-classic/hubs/integrations/other-integrations.html b/docs/expensify-classic/hubs/integrations/other-integrations.html
deleted file mode 100644
index 86641ee60b7d..000000000000
--- a/docs/expensify-classic/hubs/integrations/other-integrations.html
+++ /dev/null
@@ -1,5 +0,0 @@
----
-layout: default
----
-
-{% include section.html %}
diff --git a/docs/expensify-classic/hubs/integrations/travel-integrations.html b/docs/expensify-classic/hubs/integrations/travel-integrations.html
deleted file mode 100644
index 86641ee60b7d..000000000000
--- a/docs/expensify-classic/hubs/integrations/travel-integrations.html
+++ /dev/null
@@ -1,5 +0,0 @@
----
-layout: default
----
-
-{% include section.html %}
diff --git a/docs/expensify-classic/hubs/workspaces/reports.html b/docs/expensify-classic/hubs/workspaces/reports.html
deleted file mode 100644
index 86641ee60b7d..000000000000
--- a/docs/expensify-classic/hubs/workspaces/reports.html
+++ /dev/null
@@ -1,5 +0,0 @@
----
-layout: default
----
-
-{% include section.html %}
diff --git a/docs/redirects.csv b/docs/redirects.csv
index c1249773bb82..9e87328e6733 100644
--- a/docs/redirects.csv
+++ b/docs/redirects.csv
@@ -217,7 +217,36 @@ https://help.expensify.com/articles/new-expensify/expenses/Set-up-your-wallet,ht
https://help.expensify.com/articles/new-expensify/expenses/Split-an-expense,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Split-an-expense
https://help.expensify.com/articles/new-expensify/expenses/Track-expenses,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Track-expenses
https://help.expensify.com/articles/new-expensify/expenses/Unlock-a-Business-Bank-Account,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Unlock-a-Business-Bank-Account
+https://help.expensify.com/expensify-classic/hubs/integrations/HR-integrations,https://help.expensify.com/expensify-classic/hubs/connections
+https://help.expensify.com/expensify-classic/hubs/integrations/accounting-integrations,https://help.expensify.com/expensify-classic/hubs/connections
+https://help.expensify.com/expensify-classic/hubs/integrations/other-integrations,https://help.expensify.com/expensify-classic/hubs/connections
+https://help.expensify.com/expensify-classic/hubs/integrations/travel-integrations,https://help.expensify.com/expensify-classic/hubs/connections
+https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/ADP,https://help.expensify.com/articles/expensify-classic/connections/ADP
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Accelo,https://help.expensify.com/expensify-classic/hubs/connections/accelo
+https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Additional-Travel-Integrations,https://help.expensify.com/articles/expensify-classic/connections/Additional-Travel-Integrations
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Certinia,https://help.expensify.com/expensify-classic/hubs/connections/certinia
+https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Egencia,https://help.expensify.com/articles/expensify-classic/connections/Egencia
+https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Global-VaTax,https://help.expensify.com/articles/expensify-classic/connections/Global-VaTax
+https://help.expensify.com/articles/expensify-classic/integrations/other-integrations/Google-Apps-SSO,https://help.expensify.com/articles/expensify-classic/connections/Google-Apps-SSO
+https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/Greenhouse,https://help.expensify.com/articles/expensify-classic/connections/Greenhouse
+https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/Gusto,https://help.expensify.com/articles/expensify-classic/connections/Gusto
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Indirect-Accounting-Integrations,https://help.expensify.com/articles/expensify-classic/connections/Indirect-Accounting-Integrations
+https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Lyft,https://help.expensify.com/articles/expensify-classic/connections/Lyft
+https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Navan,https://help.expensify.com/articles/expensify-classic/connections/Navan
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/NetSuite,https://help.expensify.com/expensify-classic/hubs/connections/netsuite
+https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/QuickBooks-Time,https://help.expensify.com/articles/expensify-classic/connections/QuickBooks-Time
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop,https://help.expensify.com/expensify-classic/hubs/connections/quickbooks-desktop
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Online,https://help.expensify.com/expensify-classic/hubs/connections/quickbooks-online
+https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/Rippling,https://help.expensify.com/articles/expensify-classic/connections/Rippling
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Sage-Intacct,https://help.expensify.com/expensify-classic/hubs/connections/sage-intacct
+https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/TravelPerk,https://help.expensify.com/articles/expensify-classic/connections/TravelPerk
+https://help.expensify.com/articles/expensify-classic/integrations/travel-integrations/Uber,https://help.expensify.com/articles/expensify-classic/connections/Uber
+https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/Workday,https://help.expensify.com/articles/expensify-classic/connections/Workday
+https://help.expensify.com/articles/expensify-classic/integrations/accounting-integrations/Xero,https://help.expensify.com/expensify-classic/hubs/connections/xero
+https://help.expensify.com/articles/expensify-classic/integrations/HR-integrations/Zenefits,https://help.expensify.com/articles/expensify-classic/connections/Zenefits
https://help.expensify.com/articles/expensify-classic/workspaces/tax-tracking,https://help.expensify.com/articles/expensify-classic/workspaces/Tax-Tracking
https://help.expensify.com/articles/expensify-classic/copilots-and-delegates/Approval-Workflows,https://help.expensify.com/articles/expensify-classic/reports/Assign-report-approvers-to-specific-employees
https://help.expensify.com/articles/expensify-classic/settings/Notification-Troubleshooting,https://help.expensify.com/articles/expensify-classic/settings/account-settings/Set-Notifications
https://help.expensify.com/articles/new-expensify/expenses/Validate-a-Business-Bank-Account,https://help.expensify.com/articles/new-expensify/expenses-&-payments/Validate-a-Business-Bank-Account
+https://help.expensify.com/articles/expensify-classic/workspaces/Expenses,https://help.expensify.com/articles/expensify-classic/workspaces/Expense-Settings
+https://help.expensify.com/articles/expensify-classic/workspaces/Reimbursement,https://help.expensify.com/articles/expensify-classic/workspaces/Configure-Reimbursement-Settings
diff --git a/ios/NewApp_AdHoc.mobileprovision.gpg b/ios/NewApp_AdHoc.mobileprovision.gpg
index 0374529721e7..d5f3c582327d 100644
Binary files a/ios/NewApp_AdHoc.mobileprovision.gpg and b/ios/NewApp_AdHoc.mobileprovision.gpg differ
diff --git a/ios/NewApp_AdHoc_Notification_Service.mobileprovision.gpg b/ios/NewApp_AdHoc_Notification_Service.mobileprovision.gpg
index 0a8c3c896f5f..8300bd34ef76 100644
Binary files a/ios/NewApp_AdHoc_Notification_Service.mobileprovision.gpg and b/ios/NewApp_AdHoc_Notification_Service.mobileprovision.gpg differ
diff --git a/ios/NewExpensify.xcodeproj/project.pbxproj b/ios/NewExpensify.xcodeproj/project.pbxproj
index f86952ca7aca..164f8485129b 100644
--- a/ios/NewExpensify.xcodeproj/project.pbxproj
+++ b/ios/NewExpensify.xcodeproj/project.pbxproj
@@ -388,6 +388,7 @@
FBC7D704E4E9CC08E91D7919 /* [CP] Copy Pods Resources */,
9FF963998EFF771D82D473D2 /* [CP-User] [RNFB] Core Configuration */,
A2BE84E8C8EFD6C81A2B41F1 /* [CP-User] [RNFB] Crashlytics Configuration */,
+ 498240F82C49553900C15857 /* Run Fullstory Asset Uploader */,
);
buildRules = (
);
@@ -620,6 +621,24 @@
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
+ 498240F82C49553900C15857 /* Run Fullstory Asset Uploader */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Run Fullstory Asset Uploader";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "\"${PODS_ROOT}/FullStory/tools/FullStoryCommandLine\" \"${CONFIGURATION_BUILD_DIR}/${WRAPPER_NAME}\"\n";
+ };
5CF45ABA52C0BB0D7B9D139A /* [Expo] Configure project */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index fb193ac125fd..0589648b2301 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageTypeAPPLCFBundleShortVersionString
- 9.0.8
+ 9.0.9CFBundleSignature????CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 9.0.8.2
+ 9.0.9.1FullStoryOrgId
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index eeacc6a590d4..ccf45c0cf8d4 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageTypeBNDLCFBundleShortVersionString
- 9.0.8
+ 9.0.9CFBundleSignature????CFBundleVersion
- 9.0.8.2
+ 9.0.9.1
diff --git a/ios/NotificationServiceExtension/Info.plist b/ios/NotificationServiceExtension/Info.plist
index 891575550ee3..fe746670e837 100644
--- a/ios/NotificationServiceExtension/Info.plist
+++ b/ios/NotificationServiceExtension/Info.plist
@@ -11,9 +11,9 @@
CFBundleName$(PRODUCT_NAME)CFBundleShortVersionString
- 9.0.8
+ 9.0.9CFBundleVersion
- 9.0.8.2
+ 9.0.9.1NSExtensionNSExtensionPointIdentifier
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 50dfc65d07b2..e7854c886c75 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -303,7 +303,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- - Plaid (5.2.1)
+ - Plaid (5.6.0)
- PromisesObjC (2.4.0)
- RCT-Folly (2022.05.16.00):
- boost
@@ -1257,7 +1257,7 @@ PODS:
- React-Codegen
- React-Core
- ReactCommon/turbomodule/core
- - react-native-geolocation (3.2.1):
+ - react-native-geolocation (3.3.0):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -1343,7 +1343,27 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- - react-native-pager-view (6.2.3):
+ - react-native-pager-view (6.3.3):
+ - glog
+ - hermes-engine
+ - RCT-Folly (= 2022.05.16.00)
+ - RCTRequired
+ - RCTTypeSafety
+ - React-Codegen
+ - React-Core
+ - React-debug
+ - React-Fabric
+ - React-graphics
+ - React-ImageManager
+ - react-native-pager-view/common (= 6.3.3)
+ - React-NativeModulesApple
+ - React-RCTFabric
+ - React-rendererdebug
+ - React-utils
+ - ReactCommon/turbomodule/bridging
+ - ReactCommon/turbomodule/core
+ - Yoga
+ - react-native-pager-view/common (6.3.3):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -1400,10 +1420,10 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- - react-native-plaid-link-sdk (11.5.0):
+ - react-native-plaid-link-sdk (11.11.0):
- glog
- hermes-engine
- - Plaid (~> 5.2.0)
+ - Plaid (~> 5.6.0)
- RCT-Folly (= 2022.05.16.00)
- RCTRequired
- RCTTypeSafety
@@ -1439,7 +1459,7 @@ PODS:
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- Yoga
- - react-native-release-profiler (0.1.6):
+ - react-native-release-profiler (0.2.1):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -1871,7 +1891,7 @@ PODS:
- RNGoogleSignin (10.0.1):
- GoogleSignIn (~> 7.0)
- React-Core
- - RNLiveMarkdown (0.1.103):
+ - RNLiveMarkdown (0.1.105):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -1889,9 +1909,9 @@ PODS:
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - RNLiveMarkdown/common (= 0.1.103)
+ - RNLiveMarkdown/common (= 0.1.105)
- Yoga
- - RNLiveMarkdown/common (0.1.103):
+ - RNLiveMarkdown/common (0.1.105):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -2034,7 +2054,7 @@ PODS:
- RNSound/Core (= 0.11.2)
- RNSound/Core (0.11.2):
- React-Core
- - RNSVG (14.1.0):
+ - RNSVG (15.4.0):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -2052,9 +2072,9 @@ PODS:
- React-utils
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- - RNSVG/common (= 14.1.0)
+ - RNSVG/common (= 15.4.0)
- Yoga
- - RNSVG/common (14.1.0):
+ - RNSVG/common (15.4.0):
- glog
- hermes-engine
- RCT-Folly (= 2022.05.16.00)
@@ -2533,7 +2553,7 @@ SPEC CHECKSUMS:
nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96
Onfido: f3af62ea1c9a419589c133e3e511e5d2c4f3f8af
onfido-react-native-sdk: 3e3b0dd70afa97410fb318d54c6a415137968ef2
- Plaid: 7829e84db6d766a751c91a402702946d2977ddcb
+ Plaid: c32f22ffce5ec67c9e6147eaf6c4d7d5f8086d89
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0
RCTRequired: ab7f915c15569f04a49669e573e6e319a53f9faa
@@ -2562,18 +2582,18 @@ SPEC CHECKSUMS:
react-native-cameraroll: f373bebbe9f6b7c3fd2a6f97c5171cda574cf957
react-native-config: 5ce986133b07fc258828b20b9506de0e683efc1c
react-native-document-picker: 8532b8af7c2c930f9e202aac484ac785b0f4f809
- react-native-geolocation: f9e92eb774cb30ac1e099f34b3a94f03b4db7eb3
+ react-native-geolocation: 580c86eb531c0aaf7a14bc76fd2983ce47ca58aa
react-native-image-picker: f8a13ff106bcc7eb00c71ce11fdc36aac2a44440
react-native-key-command: 28ccfa09520e7d7e30739480dea4df003493bfe8
react-native-keyboard-controller: 47c01b0741ae5fc84e53cf282e61cfa5c2edb19b
react-native-launch-arguments: 5f41e0abf88a15e3c5309b8875d6fd5ac43df49d
react-native-netinfo: 02d31de0e08ab043d48f2a1a8baade109d7b6ca5
- react-native-pager-view: ccd4bbf9fc7effaf8f91f8dae43389844d9ef9fa
+ react-native-pager-view: c7372cab7caef173f7f81d78520fe21f08805020
react-native-pdf: 762369633665ec02ac227aefe2f4558b92475c23
react-native-performance: fb21ff0c9bd7a10789c69d948f25b0067d29f7a9
- react-native-plaid-link-sdk: 2a91ef7e257ae16d180a1ca14ba3041ae0836fbf
+ react-native-plaid-link-sdk: ba40d1b13cca4b946974fafd9ae278e0fb697d87
react-native-quick-sqlite: e3ab3e0a29d8c705f47a60aaa6ceaa42eb6a9ec1
- react-native-release-profiler: 14ccdc0eeb03bedf625cf68d53d80275a81b19dd
+ react-native-release-profiler: a77d4f291b92e48d3d4a574deed19bd1b513ac98
react-native-render-html: 96c979fe7452a0a41559685d2f83b12b93edac8c
react-native-safe-area-context: 9d79895b60b8be151fdf6faef9d2d0591eeecc63
react-native-view-shot: 6b7ed61d77d88580fed10954d45fad0eb2d47688
@@ -2614,7 +2634,7 @@ SPEC CHECKSUMS:
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
RNGestureHandler: 74b7b3d06d667ba0bbf41da7718f2607ae0dfe8f
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
- RNLiveMarkdown: f12157fc91b72e19705c9cc8c98034c4c1669d5a
+ RNLiveMarkdown: bae86068a0b80cda3d4875ac2a5a398955a94922
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
rnmapbox-maps: df8fe93dbd251f25022f4023d31bc04160d4d65c
RNPermissions: d2392b754e67bc14491f5b12588bef2864e783f3
@@ -2623,7 +2643,7 @@ SPEC CHECKSUMS:
RNScreens: abd354e98519ed267600b7ee64fdcb8e060b1218
RNShare: 2a4cdfc0626ad56b0ef583d424f2038f772afe58
RNSound: 6c156f925295bdc83e8e422e7d8b38d33bc71852
- RNSVG: 18f1381e046be2f1c30b4724db8d0c966238089f
+ RNSVG: 8c067e7203053d4c82f456cbeab1fe509ac797dd
SDWebImage: 750adf017a315a280c60fde706ab1e552a3ae4e9
SDWebImageAVIFCoder: 8348fef6d0ec69e129c66c9fe4d74fbfbf366112
SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c
diff --git a/package-lock.json b/package-lock.json
index 3076816e9ed4..2ced5738cca8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,19 +1,19 @@
{
"name": "new.expensify",
- "version": "9.0.8-2",
+ "version": "9.0.9-1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "9.0.8-2",
+ "version": "9.0.9-1",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@dotlottie/react-player": "^1.6.3",
- "@expensify/react-native-live-markdown": "0.1.103",
+ "@expensify/react-native-live-markdown": "0.1.105",
"@expo/metro-runtime": "~3.1.1",
"@formatjs/intl-datetimeformat": "^6.10.0",
"@formatjs/intl-listformat": "^7.2.2",
@@ -31,7 +31,7 @@
"@onfido/react-native-sdk": "10.6.0",
"@react-native-camera-roll/camera-roll": "7.4.0",
"@react-native-clipboard/clipboard": "^1.13.2",
- "@react-native-community/geolocation": "3.2.1",
+ "@react-native-community/geolocation": "3.3.0",
"@react-native-community/netinfo": "11.2.1",
"@react-native-firebase/analytics": "^12.3.0",
"@react-native-firebase/app": "^12.3.0",
@@ -55,7 +55,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "2.0.39",
+ "expensify-common": "2.0.49",
"expo": "^50.0.3",
"expo-av": "~13.10.4",
"expo-image": "1.11.0",
@@ -103,22 +103,22 @@
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "2.0.56",
- "react-native-pager-view": "6.2.3",
+ "react-native-pager-view": "6.3.3",
"react-native-pdf": "6.7.3",
"react-native-performance": "^5.1.0",
"react-native-permissions": "^3.10.0",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf",
- "react-native-plaid-link-sdk": "11.5.0",
- "react-native-qrcode-svg": "^6.2.0",
+ "react-native-plaid-link-sdk": "11.11.0",
+ "react-native-qrcode-svg": "git+https://github.com/Expensify/react-native-qrcode-svg",
"react-native-quick-sqlite": "git+https://github.com/margelo/react-native-quick-sqlite#abc91857d4b3efb2020ec43abd2a508563b64316",
"react-native-reanimated": "^3.8.0",
- "react-native-release-profiler": "^0.1.6",
+ "react-native-release-profiler": "^0.2.1",
"react-native-render-html": "6.3.1",
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "3.32.0",
"react-native-share": "^10.0.2",
"react-native-sound": "^0.11.2",
- "react-native-svg": "14.1.0",
+ "react-native-svg": "15.4.0",
"react-native-tab-view": "^3.5.2",
"react-native-url-polyfill": "^2.0.0",
"react-native-view-shot": "3.8.0",
@@ -155,7 +155,7 @@
"@octokit/core": "4.0.4",
"@octokit/plugin-paginate-rest": "3.1.0",
"@octokit/plugin-throttling": "4.1.0",
- "@perf-profiler/profiler": "^0.10.10",
+ "@perf-profiler/profiler": "^0.10.11",
"@perf-profiler/reporter": "^0.9.0",
"@perf-profiler/types": "^0.8.0",
"@react-native-community/eslint-config": "3.2.0",
@@ -212,7 +212,7 @@
"diff-so-fancy": "^1.3.0",
"dotenv": "^16.0.3",
"electron": "^29.4.1",
- "electron-builder": "24.13.2",
+ "electron-builder": "25.0.0",
"eslint": "^8.57.0",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-config-expensify": "^2.0.52",
@@ -2982,8 +2982,9 @@
},
"node_modules/@develar/schema-utils": {
"version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz",
+ "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ajv": "^6.12.0",
"ajv-keywords": "^3.4.1"
@@ -2998,8 +2999,9 @@
},
"node_modules/@develar/schema-utils/node_modules/ajv": {
"version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
- "license": "MIT",
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -3013,16 +3015,18 @@
},
"node_modules/@develar/schema-utils/node_modules/ajv-keywords": {
"version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
"dev": true,
- "license": "MIT",
"peerDependencies": {
"ajv": "^6.9.1"
}
},
"node_modules/@develar/schema-utils/node_modules/json-schema-traverse": {
"version": "0.4.1",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "dev": true
},
"node_modules/@discoveryjs/json-ext": {
"version": "0.5.7",
@@ -3107,9 +3111,10 @@
}
},
"node_modules/@electron/asar": {
- "version": "3.2.8",
+ "version": "3.2.10",
+ "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.2.10.tgz",
+ "integrity": "sha512-mvBSwIBUeiRscrCeJE1LwctAriBj65eUDm0Pc11iE5gRwzkmsdbS7FnZ1XUWjpSeQWL1L5g12Fc/SchPM9DUOw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"commander": "^5.0.0",
"glob": "^7.1.6",
@@ -3124,8 +3129,9 @@
},
"node_modules/@electron/asar/node_modules/commander": {
"version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+ "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 6"
}
@@ -3188,9 +3194,10 @@
}
},
"node_modules/@electron/notarize": {
- "version": "2.2.1",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.3.2.tgz",
+ "integrity": "sha512-zfayxCe19euNwRycCty1C7lF7snk9YwfRpB5M8GLr1a4ICH63znxaPNAubrMvj0yDvVozqfgsdYpXVUnpWBDpg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"debug": "^4.1.1",
"fs-extra": "^9.0.1",
@@ -3201,9 +3208,10 @@
}
},
"node_modules/@electron/osx-sign": {
- "version": "1.0.5",
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.0.tgz",
+ "integrity": "sha512-TEXhxlYSDRr9JWK5nWdOv5MtuUdaZ412uxIIEQ0hLt80o0HYWtQJBlW5QmrQDMtebzATaOjKG9UfCzLyA90zWQ==",
"dev": true,
- "license": "BSD-2-Clause",
"dependencies": {
"compare-version": "^0.1.2",
"debug": "^4.3.4",
@@ -3222,8 +3230,9 @@
},
"node_modules/@electron/osx-sign/node_modules/fs-extra": {
"version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -3235,8 +3244,9 @@
},
"node_modules/@electron/osx-sign/node_modules/isbinaryfile": {
"version": "4.0.10",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz",
+ "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 8.0.0"
},
@@ -3244,21 +3254,172 @@
"url": "https://github.com/sponsors/gjtorikian/"
}
},
+ "node_modules/@electron/rebuild": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.0.tgz",
+ "integrity": "sha512-zF4x3QupRU3uNGaP5X1wjpmcjfw1H87kyqZ00Tc3HvriV+4gmOGuvQjGNkrJuXdsApssdNyVwLsy+TaeTGGcVw==",
+ "dev": true,
+ "dependencies": {
+ "@malept/cross-spawn-promise": "^2.0.0",
+ "chalk": "^4.0.0",
+ "debug": "^4.1.1",
+ "detect-libc": "^2.0.1",
+ "fs-extra": "^10.0.0",
+ "got": "^11.7.0",
+ "node-abi": "^3.45.0",
+ "node-api-version": "^0.2.0",
+ "node-gyp": "^9.0.0",
+ "ora": "^5.1.0",
+ "read-binary-file-arch": "^1.0.6",
+ "semver": "^7.3.5",
+ "tar": "^6.0.5",
+ "yargs": "^17.0.1"
+ },
+ "bin": {
+ "electron-rebuild": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=12.13.0"
+ }
+ },
+ "node_modules/@electron/rebuild/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/@electron/rebuild/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/@electron/rebuild/node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/@electron/rebuild/node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/@electron/rebuild/node_modules/fs-extra": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@electron/rebuild/node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@electron/rebuild/node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/@electron/universal": {
- "version": "1.5.1",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.1.tgz",
+ "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "@electron/asar": "^3.2.1",
- "@malept/cross-spawn-promise": "^1.1.0",
+ "@electron/asar": "^3.2.7",
+ "@malept/cross-spawn-promise": "^2.0.0",
"debug": "^4.3.1",
- "dir-compare": "^3.0.0",
- "fs-extra": "^9.0.1",
- "minimatch": "^3.0.4",
- "plist": "^3.0.4"
+ "dir-compare": "^4.2.0",
+ "fs-extra": "^11.1.1",
+ "minimatch": "^9.0.3",
+ "plist": "^3.1.0"
},
"engines": {
- "node": ">=8.6"
+ "node": ">=16.4"
+ }
+ },
+ "node_modules/@electron/universal/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@electron/universal/node_modules/fs-extra": {
+ "version": "11.2.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
+ "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=14.14"
+ }
+ },
+ "node_modules/@electron/universal/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@emotion/use-insertion-effect-with-fallbacks": {
@@ -3785,9 +3946,9 @@
}
},
"node_modules/@expensify/react-native-live-markdown": {
- "version": "0.1.103",
- "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.103.tgz",
- "integrity": "sha512-w9jQoxBE9LghfL8UdYbG+8A+CApmER/XMH8N7/bINn7w57+FnnBa5ckPWx6/UYX7OYsmYxSaHJLQkJEXYlDRZg==",
+ "version": "0.1.105",
+ "resolved": "https://registry.npmjs.org/@expensify/react-native-live-markdown/-/react-native-live-markdown-0.1.105.tgz",
+ "integrity": "sha512-4cecVQFQQjdszUHtkHVT7sMwKntGCfxH62DJvbpa6H3eTuz3RCHrzWOZBQGRDVpn0aM3nwVgcWZSvNsDvT8Ziw==",
"workspaces": [
"parser",
"example",
@@ -6124,28 +6285,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/console/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/console/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/@jest/console/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -6249,28 +6388,6 @@
}
}
},
- "node_modules/@jest/core/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/core/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/@jest/core/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -6339,86 +6456,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/create-cache-key-function/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/create-cache-key-function/node_modules/@types/yargs": {
- "version": "17.0.31",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@jest/create-cache-key-function/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/create-cache-key-function/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/create-cache-key-function/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/create-cache-key-function/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/@jest/create-cache-key-function/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/create-cache-key-function/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@jest/environment": {
"version": "29.7.0",
"license": "MIT",
@@ -6432,86 +6469,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/environment/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/environment/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@jest/environment/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/environment/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/environment/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/environment/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/@jest/environment/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/environment/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@jest/expect": {
"version": "29.6.2",
"license": "MIT",
@@ -6548,86 +6505,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/fake-timers/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/fake-timers/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@jest/fake-timers/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/fake-timers/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/fake-timers/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/fake-timers/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/@jest/fake-timers/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/fake-timers/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@jest/globals": {
"version": "29.5.0",
"license": "MIT",
@@ -6641,86 +6518,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/globals/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/globals/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@jest/globals/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/globals/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/globals/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/globals/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/@jest/globals/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/globals/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@jest/reporters": {
"version": "29.4.1",
"license": "MIT",
@@ -6762,28 +6559,6 @@
}
}
},
- "node_modules/@jest/reporters/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/reporters/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/@jest/reporters/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -6903,86 +6678,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/test-result/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/test-result/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/@jest/test-result/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/@jest/test-result/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/@jest/test-result/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/@jest/test-result/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/@jest/test-result/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/@jest/test-result/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/@jest/test-sequencer": {
"version": "29.4.1",
"license": "MIT",
@@ -7020,28 +6715,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/@jest/transform/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/@jest/transform/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/@jest/transform/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -7119,10 +6792,7 @@
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz",
"integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==",
- "dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"@jest/schemas": "^29.6.3",
"@types/istanbul-lib-coverage": "^2.0.0",
@@ -7137,10 +6807,7 @@
},
"node_modules/@jest/types/node_modules/ansi-styles": {
"version": "4.3.0",
- "dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -7153,10 +6820,7 @@
},
"node_modules/@jest/types/node_modules/chalk": {
"version": "4.1.2",
- "dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -7170,10 +6834,7 @@
},
"node_modules/@jest/types/node_modules/color-convert": {
"version": "2.0.1",
- "dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"color-name": "~1.1.4"
},
@@ -7183,27 +6844,18 @@
},
"node_modules/@jest/types/node_modules/color-name": {
"version": "1.1.4",
- "dev": true,
- "license": "MIT",
- "optional": true,
- "peer": true
+ "license": "MIT"
},
"node_modules/@jest/types/node_modules/has-flag": {
"version": "4.0.0",
- "dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"engines": {
"node": ">=8"
}
},
"node_modules/@jest/types/node_modules/supports-color": {
"version": "7.2.0",
- "dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -7418,7 +7070,9 @@
}
},
"node_modules/@malept/cross-spawn-promise": {
- "version": "1.1.1",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz",
+ "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==",
"dev": true,
"funding": [
{
@@ -7430,18 +7084,18 @@
"url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund"
}
],
- "license": "Apache-2.0",
"dependencies": {
"cross-spawn": "^7.0.1"
},
"engines": {
- "node": ">= 10"
+ "node": ">= 12.13.0"
}
},
"node_modules/@malept/flatpak-bundler": {
"version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz",
+ "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==",
"dev": true,
- "license": "MIT",
"dependencies": {
"debug": "^4.1.1",
"fs-extra": "^9.0.0",
@@ -7909,13 +7563,13 @@
}
},
"node_modules/@perf-profiler/android": {
- "version": "0.12.1",
- "resolved": "https://registry.npmjs.org/@perf-profiler/android/-/android-0.12.1.tgz",
- "integrity": "sha512-t4E2tfj9UdJw5JjhFPLMzrsu3NkKSyiZyeIyd70HX9d3anWqNK47XuQV+qkDPMjWaoU+CTlj1SuNnIOqEkCpSA==",
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@perf-profiler/android/-/android-0.13.0.tgz",
+ "integrity": "sha512-4lUQjJNHFAYB5npts5JLrPaPNpIOEAAjfpeTQOOgBNLT1NW50WWSGuvV2pAdnMi7T28cXs3aUziJJ30cNrSvNg==",
"dev": true,
"dependencies": {
"@perf-profiler/logger": "^0.3.3",
- "@perf-profiler/profiler": "^0.10.10",
+ "@perf-profiler/profiler": "^0.10.11",
"@perf-profiler/types": "^0.8.0",
"commander": "^12.0.0",
"lodash": "^4.17.21"
@@ -7934,24 +7588,24 @@
}
},
"node_modules/@perf-profiler/ios": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@perf-profiler/ios/-/ios-0.3.2.tgz",
- "integrity": "sha512-2jYyHXFO3xe5BdvU1Ttt+Uw2nAf10B3/mcx4FauJwSdJ+nlOAKIvxmZDvMcipCZZ63uc+HWsYndhziJZVQ7VUw==",
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@perf-profiler/ios/-/ios-0.3.3.tgz",
+ "integrity": "sha512-dbb9lVKOyj1VjinuxrnbfI3FT0+uhH3xclqLQH7rQFA4d93dusjC/s3RzlnCXRNPFPDy5TTmkiIg3xM/6P3/2g==",
"dev": true,
"dependencies": {
- "@perf-profiler/ios-instruments": "^0.3.2",
+ "@perf-profiler/ios-instruments": "^0.3.3",
"@perf-profiler/logger": "^0.3.3",
"@perf-profiler/types": "^0.8.0"
}
},
"node_modules/@perf-profiler/ios-instruments": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/@perf-profiler/ios-instruments/-/ios-instruments-0.3.2.tgz",
- "integrity": "sha512-uox5arQscpRuGWfzBrTpsn6eJq0ErdjPlU0FMbN4Cv5akQC11ejKWmgV6y4FR/0YIET9uiiXMtnwyEBgUunYGQ==",
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/@perf-profiler/ios-instruments/-/ios-instruments-0.3.3.tgz",
+ "integrity": "sha512-e3UmlWuNUOuNbJPWg6aLOVd9wRKe3RYCqwwUgxMNIAwa5QBxaVYBf2pt3+HRsYReh2qm1yvqW7LU9zP+AJ7/7g==",
"dev": true,
"dependencies": {
"@perf-profiler/logger": "^0.3.3",
- "@perf-profiler/profiler": "^0.10.10",
+ "@perf-profiler/profiler": "^0.10.11",
"@perf-profiler/types": "^0.8.0",
"commander": "^12.0.0",
"fast-xml-parser": "^4.2.7"
@@ -7992,13 +7646,13 @@
}
},
"node_modules/@perf-profiler/profiler": {
- "version": "0.10.10",
- "resolved": "https://registry.npmjs.org/@perf-profiler/profiler/-/profiler-0.10.10.tgz",
- "integrity": "sha512-kvVC6VQ7pBdthcWEcLTua+iDj0ZkcmYYL9gXHa9Dl7jYkZI4cOeslJZ1vuGfIcC168JwAVrB8UYhgoSgss/MWQ==",
+ "version": "0.10.11",
+ "resolved": "https://registry.npmjs.org/@perf-profiler/profiler/-/profiler-0.10.11.tgz",
+ "integrity": "sha512-nu/zakhG5wRi0tCw4SjTCZJh9e/x9YABAOChh3lGI6CESsFzc1Gi2Vrr+2sytN8dpiTDYCCbECC2EalD7ZKvtg==",
"dev": true,
"dependencies": {
- "@perf-profiler/android": "^0.12.1",
- "@perf-profiler/ios": "^0.3.2",
+ "@perf-profiler/android": "^0.13.0",
+ "@perf-profiler/ios": "^0.3.3",
"@perf-profiler/types": "^0.8.0"
}
},
@@ -9073,9 +8727,9 @@
}
},
"node_modules/@react-native-community/cli-server-api/node_modules/ws": {
- "version": "7.5.9",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
- "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"engines": {
"node": ">=8.3.0"
},
@@ -9583,9 +9237,9 @@
"license": "MIT"
},
"node_modules/@react-native-community/geolocation": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/@react-native-community/geolocation/-/geolocation-3.2.1.tgz",
- "integrity": "sha512-/+HNzuRl4UCMma7KK+KYL8k2nxAGuW+DGxqmqfpiqKBlCkCUbuFHaZZdqVD6jpsn9r/ghe583ECLmd9SV9I4Bw==",
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-community/geolocation/-/geolocation-3.3.0.tgz",
+ "integrity": "sha512-7DFeuotH7m7ImoXffN3TmlGSFn1XjvsaphPort0XZKipssYbdHiKhVVWG+jzisvDhcXikUc6nbUJgddVBL6RDg==",
"engines": {
"node": ">=18.0.0"
},
@@ -17655,8 +17309,9 @@
},
"node_modules/@types/debug": {
"version": "4.1.12",
+ "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
+ "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@types/ms": "*"
}
@@ -17743,8 +17398,9 @@
},
"node_modules/@types/fs-extra": {
"version": "9.0.13",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
+ "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@types/node": "*"
}
@@ -17931,8 +17587,9 @@
},
"node_modules/@types/ms": {
"version": "0.7.34",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
+ "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==",
+ "dev": true
},
"node_modules/@types/node": {
"version": "20.11.5",
@@ -17963,8 +17620,9 @@
},
"node_modules/@types/plist": {
"version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz",
+ "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"@types/node": "*",
@@ -18172,9 +17830,10 @@
"dev": true
},
"node_modules/@types/verror": {
- "version": "1.10.9",
+ "version": "1.10.10",
+ "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.10.tgz",
+ "integrity": "sha512-l4MM0Jppn18hb9xmM6wwD1uTdShpf9Pn80aXTStnK1C94gtPvJcV2FrDmbOQUAQfJ1cKZHktkQUDwEqaAKXMMg==",
"dev": true,
- "license": "MIT",
"optional": true
},
"node_modules/@types/webpack": {
@@ -18210,10 +17869,7 @@
"version": "17.0.32",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz",
"integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==",
- "dev": true,
"license": "MIT",
- "optional": true,
- "peer": true,
"dependencies": {
"@types/yargs-parser": "*"
}
@@ -18947,8 +18603,9 @@
},
"node_modules/7zip-bin": {
"version": "5.2.0",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz",
+ "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==",
+ "dev": true
},
"node_modules/abab": {
"version": "2.0.6",
@@ -18956,8 +18613,8 @@
},
"node_modules/abbrev": {
"version": "1.1.1",
- "license": "ISC",
- "optional": true
+ "devOptional": true,
+ "license": "ISC"
},
"node_modules/abort-controller": {
"version": "3.0.0",
@@ -19075,6 +18732,18 @@
"node": ">= 6.0.0"
}
},
+ "node_modules/agentkeepalive": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz",
+ "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==",
+ "dev": true,
+ "dependencies": {
+ "humanize-ms": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
+ },
"node_modules/aggregate-error": {
"version": "3.1.0",
"license": "MIT",
@@ -19295,29 +18964,32 @@
}
},
"node_modules/app-builder-bin": {
- "version": "4.0.0",
- "dev": true,
- "license": "MIT"
+ "version": "5.0.0-alpha.4",
+ "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.4.tgz",
+ "integrity": "sha512-4MitKmOtfTdMONrtRoiaqJ6HtlVZXgrNX1PNdEzEHSAoXU85x7s+mo0IhAS9K9qgjyTVuLrM1E/HAMp5qGyoOA==",
+ "dev": true
},
"node_modules/app-builder-lib": {
- "version": "24.13.2",
+ "version": "25.0.0",
+ "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-25.0.0.tgz",
+ "integrity": "sha512-GIx0n/QvbeObY8rQTTp08UPn4pS9xSGZLq6cPRy/CyX/mTNN9pO/uU28MWgqjnYXk0bf/595vzDdAijuDyz5Zw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@develar/schema-utils": "~2.6.5",
- "@electron/notarize": "2.2.1",
- "@electron/osx-sign": "1.0.5",
- "@electron/universal": "1.5.1",
+ "@electron/notarize": "2.3.2",
+ "@electron/osx-sign": "1.3.0",
+ "@electron/rebuild": "3.6.0",
+ "@electron/universal": "2.0.1",
"@malept/flatpak-bundler": "^0.4.0",
"@types/fs-extra": "9.0.13",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.9",
- "builder-util": "24.13.1",
- "builder-util-runtime": "9.2.4",
+ "builder-util": "25.0.0",
+ "builder-util-runtime": "9.2.5",
"chromium-pickle-js": "^0.2.0",
"debug": "^4.3.4",
"ejs": "^3.1.8",
- "electron-publish": "24.13.1",
+ "electron-publish": "25.0.0",
"form-data": "^4.0.0",
"fs-extra": "^10.1.0",
"hosted-git-info": "^4.1.0",
@@ -19325,8 +18997,9 @@
"isbinaryfile": "^5.0.0",
"js-yaml": "^4.1.0",
"lazy-val": "^1.0.5",
- "minimatch": "^5.1.1",
- "read-config-file": "6.3.2",
+ "minimatch": "^10.0.0",
+ "read-config-file": "6.4.0",
+ "resedit": "^1.7.0",
"sanitize-filename": "^1.6.3",
"semver": "^7.3.8",
"tar": "^6.1.12",
@@ -19336,27 +19009,30 @@
"node": ">=14.0.0"
},
"peerDependencies": {
- "dmg-builder": "24.13.2",
- "electron-builder-squirrel-windows": "24.13.2"
+ "dmg-builder": "25.0.0",
+ "electron-builder-squirrel-windows": "25.0.0"
}
},
"node_modules/app-builder-lib/node_modules/argparse": {
"version": "2.0.1",
- "dev": true,
- "license": "Python-2.0"
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
},
"node_modules/app-builder-lib/node_modules/brace-expansion": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/app-builder-lib/node_modules/form-data": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"dev": true,
- "license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
@@ -19368,8 +19044,9 @@
},
"node_modules/app-builder-lib/node_modules/fs-extra": {
"version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -19381,8 +19058,9 @@
},
"node_modules/app-builder-lib/node_modules/js-yaml": {
"version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -19391,14 +19069,18 @@
}
},
"node_modules/app-builder-lib/node_modules/minimatch": {
- "version": "5.1.6",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz",
+ "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==",
"dev": true,
- "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
- "node": ">=10"
+ "node": "20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/app-root-dir": {
@@ -19418,13 +19100,14 @@
},
"node_modules/aproba": {
"version": "1.2.0",
- "license": "ISC",
- "optional": true
+ "devOptional": true,
+ "license": "ISC"
},
"node_modules/archiver": {
"version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.2.tgz",
+ "integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"archiver-utils": "^2.1.0",
@@ -19441,8 +19124,9 @@
},
"node_modules/archiver-utils": {
"version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
+ "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"glob": "^7.1.4",
@@ -19462,8 +19146,9 @@
},
"node_modules/archiver/node_modules/readable-stream": {
"version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"inherits": "^2.0.3",
@@ -19735,8 +19420,9 @@
},
"node_modules/assert-plus": {
"version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+ "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==",
"dev": true,
- "license": "MIT",
"optional": true,
"engines": {
"node": ">=0.8"
@@ -19779,8 +19465,9 @@
},
"node_modules/astral-regex": {
"version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
+ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
"dev": true,
- "license": "MIT",
"optional": true,
"engines": {
"node": ">=8"
@@ -19800,8 +19487,9 @@
},
"node_modules/async-exit-hook": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz",
+ "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=0.12.0"
}
@@ -20942,13 +20630,15 @@
},
"node_modules/bluebird": {
"version": "3.7.2",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
+ "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
+ "dev": true
},
"node_modules/bluebird-lst": {
"version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz",
+ "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"bluebird": "^3.5.5"
}
@@ -21268,17 +20958,6 @@
"node": "*"
}
},
- "node_modules/buffer-equal": {
- "version": "1.0.1",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
"node_modules/buffer-fill": {
"version": "1.0.0",
"license": "MIT"
@@ -21292,15 +20971,16 @@
"license": "MIT"
},
"node_modules/builder-util": {
- "version": "24.13.1",
+ "version": "25.0.0",
+ "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-25.0.0.tgz",
+ "integrity": "sha512-cI8zIsipo/gciZ5jGEA1qYL5Em1N6cWoNMpeJWZAfOs3H9s5zQWKnAS7rTdlJpsJ88gEmL5/32yeXUF2Uzxw6w==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@types/debug": "^4.1.6",
"7zip-bin": "~5.2.0",
- "app-builder-bin": "4.0.0",
+ "app-builder-bin": "v5.0.0-alpha.4",
"bluebird-lst": "^1.0.9",
- "builder-util-runtime": "9.2.4",
+ "builder-util-runtime": "9.2.5",
"chalk": "^4.1.2",
"cross-spawn": "^7.0.3",
"debug": "^4.3.4",
@@ -21315,9 +20995,10 @@
}
},
"node_modules/builder-util-runtime": {
- "version": "9.2.4",
+ "version": "9.2.5",
+ "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.2.5.tgz",
+ "integrity": "sha512-HjIDfhvqx/8B3TDN4GbABQcgpewTU4LMRTQPkVpKYV3lsuxEJoIfvg09GyWTNmfVNSUAYf+fbTN//JX4TH20pg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"debug": "^4.3.4",
"sax": "^1.2.4"
@@ -21328,8 +21009,9 @@
},
"node_modules/builder-util/node_modules/ansi-styles": {
"version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -21342,13 +21024,15 @@
},
"node_modules/builder-util/node_modules/argparse": {
"version": "2.0.1",
- "dev": true,
- "license": "Python-2.0"
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
},
"node_modules/builder-util/node_modules/chalk": {
"version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -21362,8 +21046,9 @@
},
"node_modules/builder-util/node_modules/color-convert": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -21373,13 +21058,15 @@
},
"node_modules/builder-util/node_modules/color-name": {
"version": "1.1.4",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"node_modules/builder-util/node_modules/fs-extra": {
"version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -21391,16 +21078,18 @@
},
"node_modules/builder-util/node_modules/has-flag": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/builder-util/node_modules/js-yaml": {
"version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -21410,8 +21099,9 @@
},
"node_modules/builder-util/node_modules/supports-color": {
"version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -21804,8 +21494,9 @@
},
"node_modules/chromium-pickle-js": {
"version": "0.2.0",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz",
+ "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==",
+ "dev": true
},
"node_modules/ci-info": {
"version": "3.8.0",
@@ -22011,8 +21702,9 @@
},
"node_modules/cli-truncate": {
"version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz",
+ "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"slice-ansi": "^3.0.0",
@@ -22165,8 +21857,8 @@
},
"node_modules/color-support": {
"version": "1.1.3",
+ "devOptional": true,
"license": "ISC",
- "optional": true,
"bin": {
"color-support": "bin.js"
}
@@ -22231,8 +21923,9 @@
},
"node_modules/compare-version": {
"version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz",
+ "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -22263,8 +21956,9 @@
},
"node_modules/compress-commons": {
"version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.2.tgz",
+ "integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"buffer-crc32": "^0.2.13",
@@ -22278,8 +21972,9 @@
},
"node_modules/compress-commons/node_modules/readable-stream": {
"version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"inherits": "^2.0.3",
@@ -22444,47 +22139,64 @@
}
},
"node_modules/config-file-ts": {
- "version": "0.2.6",
+ "version": "0.2.8-rc1",
+ "resolved": "https://registry.npmjs.org/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz",
+ "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "glob": "^10.3.10",
- "typescript": "^5.3.3"
+ "glob": "^10.3.12",
+ "typescript": "^5.4.3"
}
},
"node_modules/config-file-ts/node_modules/brace-expansion": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/config-file-ts/node_modules/glob": {
- "version": "10.3.10",
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
"dev": true,
- "license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
- "jackspeak": "^2.3.5",
- "minimatch": "^9.0.1",
- "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
- "path-scurry": "^1.10.1"
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
- "engines": {
- "node": ">=16 || 14 >=14.17"
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/config-file-ts/node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "dev": true,
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
}
},
"node_modules/config-file-ts/node_modules/minimatch": {
- "version": "9.0.3",
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"dev": true,
- "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -22496,9 +22208,10 @@
}
},
"node_modules/config-file-ts/node_modules/minipass": {
- "version": "7.0.4",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"dev": true,
- "license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
@@ -22587,8 +22300,8 @@
},
"node_modules/console-control-strings": {
"version": "1.1.0",
- "license": "ISC",
- "optional": true
+ "devOptional": true,
+ "license": "ISC"
},
"node_modules/constants-browserify": {
"version": "1.0.0",
@@ -22806,8 +22519,9 @@
},
"node_modules/crc": {
"version": "3.8.0",
+ "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
+ "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"buffer": "^5.1.0"
@@ -22815,8 +22529,9 @@
},
"node_modules/crc-32": {
"version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"dev": true,
- "license": "Apache-2.0",
"peer": true,
"bin": {
"crc32": "bin/crc32.njs"
@@ -22827,8 +22542,9 @@
},
"node_modules/crc32-stream": {
"version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.3.tgz",
+ "integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"crc-32": "^1.2.0",
@@ -22840,8 +22556,9 @@
},
"node_modules/crc32-stream/node_modules/readable-stream": {
"version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"inherits": "^2.0.3",
@@ -23581,8 +23298,8 @@
},
"node_modules/delegates": {
"version": "1.0.0",
- "license": "MIT",
- "optional": true
+ "devOptional": true,
+ "license": "MIT"
},
"node_modules/denodeify": {
"version": "1.2.1",
@@ -23643,8 +23360,8 @@
},
"node_modules/detect-libc": {
"version": "2.0.1",
+ "devOptional": true,
"license": "Apache-2.0",
- "optional": true,
"engines": {
"node": ">=8"
}
@@ -23737,12 +23454,13 @@
"license": "MIT"
},
"node_modules/dir-compare": {
- "version": "3.3.0",
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz",
+ "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "buffer-equal": "^1.0.0",
- "minimatch": "^3.0.4"
+ "minimatch": "^3.0.5",
+ "p-limit": "^3.1.0 "
}
},
"node_modules/dir-glob": {
@@ -23756,13 +23474,14 @@
}
},
"node_modules/dmg-builder": {
- "version": "24.13.2",
+ "version": "25.0.0",
+ "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-25.0.0.tgz",
+ "integrity": "sha512-kXETWCy/JIXS8PHYc8Y0EdSWO02gpf4jleW74hkIp6o9WWTjAdBRw2fAcRBNIEBUJtVHFrgCYsEWh0wKFUB0+A==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "app-builder-lib": "24.13.2",
- "builder-util": "24.13.1",
- "builder-util-runtime": "9.2.4",
+ "app-builder-lib": "25.0.0",
+ "builder-util": "25.0.0",
+ "builder-util-runtime": "9.2.5",
"fs-extra": "^10.1.0",
"iconv-lite": "^0.6.2",
"js-yaml": "^4.1.0"
@@ -23773,13 +23492,15 @@
},
"node_modules/dmg-builder/node_modules/argparse": {
"version": "2.0.1",
- "dev": true,
- "license": "Python-2.0"
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
},
"node_modules/dmg-builder/node_modules/fs-extra": {
"version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -23791,8 +23512,9 @@
},
"node_modules/dmg-builder/node_modules/js-yaml": {
"version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -23802,8 +23524,9 @@
},
"node_modules/dmg-license": {
"version": "1.0.11",
+ "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz",
+ "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==",
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -23827,8 +23550,9 @@
},
"node_modules/dmg-license/node_modules/ajv": {
"version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
@@ -23843,8 +23567,9 @@
},
"node_modules/dmg-license/node_modules/json-schema-traverse": {
"version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
"dev": true,
- "license": "MIT",
"optional": true
},
"node_modules/dns-packet": {
@@ -23959,20 +23684,31 @@
}
},
"node_modules/dotenv": {
- "version": "16.3.1",
+ "version": "16.4.5",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
+ "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
"dev": true,
- "license": "BSD-2-Clause",
"engines": {
"node": ">=12"
},
"funding": {
- "url": "https://github.com/motdotla/dotenv?sponsor=1"
+ "url": "https://dotenvx.com"
}
},
"node_modules/dotenv-expand": {
- "version": "5.1.0",
+ "version": "11.0.6",
+ "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.6.tgz",
+ "integrity": "sha512-8NHi73otpWsZGBSZwwknTXS5pqMOrk9+Ssrna8xCaxkzEpU9OTf9R5ArQGVw03//Zmk9MOwLPng9WwndvpAJ5g==",
"dev": true,
- "license": "BSD-2-Clause"
+ "dependencies": {
+ "dotenv": "^16.4.4"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
},
"node_modules/duplexer": {
"version": "0.1.2",
@@ -24040,19 +23776,20 @@
}
},
"node_modules/electron-builder": {
- "version": "24.13.2",
+ "version": "25.0.0",
+ "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-25.0.0.tgz",
+ "integrity": "sha512-3nEqF6KnoM206mLz1C70VXWCzXmH2boL82wkpgLB1GXgK3dly6ay/cepI+2BmQT4iWkIHeG8qH9bPjPj0hn+1A==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "app-builder-lib": "24.13.2",
- "builder-util": "24.13.1",
- "builder-util-runtime": "9.2.4",
+ "app-builder-lib": "25.0.0",
+ "builder-util": "25.0.0",
+ "builder-util-runtime": "9.2.5",
"chalk": "^4.1.2",
- "dmg-builder": "24.13.2",
+ "dmg-builder": "25.0.0",
"fs-extra": "^10.1.0",
"is-ci": "^3.0.0",
"lazy-val": "^1.0.5",
- "read-config-file": "6.3.2",
+ "read-config-file": "6.4.0",
"simple-update-notifier": "2.0.0",
"yargs": "^17.6.2"
},
@@ -24065,21 +23802,23 @@
}
},
"node_modules/electron-builder-squirrel-windows": {
- "version": "24.13.2",
+ "version": "25.0.0",
+ "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-25.0.0.tgz",
+ "integrity": "sha512-bfARwAdye1UkFQZ7NedHZBcOek2lvDDeg/pCaXT4Nrki7gdwrvVY/Be/QJm7Smc6IR/mviozbL9ykUHQ/FSsbw==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
- "app-builder-lib": "24.13.2",
+ "app-builder-lib": "25.0.0",
"archiver": "^5.3.1",
- "builder-util": "24.13.1",
+ "builder-util": "25.0.0",
"fs-extra": "^10.1.0"
}
},
"node_modules/electron-builder-squirrel-windows/node_modules/fs-extra": {
"version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"graceful-fs": "^4.2.0",
@@ -24168,13 +23907,14 @@
}
},
"node_modules/electron-publish": {
- "version": "24.13.1",
+ "version": "25.0.0",
+ "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-25.0.0.tgz",
+ "integrity": "sha512-8wq3pVLq9bpd/jNKJGIXbeL8B8AovLojtCDkVSuSgrLtxEndqy5JfuadUKPAgbmh1zjholNAHsfHH9FS5yeYAg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"@types/fs-extra": "^9.0.11",
- "builder-util": "24.13.1",
- "builder-util-runtime": "9.2.4",
+ "builder-util": "25.0.0",
+ "builder-util-runtime": "9.2.5",
"chalk": "^4.1.2",
"fs-extra": "^10.1.0",
"lazy-val": "^1.0.5",
@@ -24183,8 +23923,9 @@
},
"node_modules/electron-publish/node_modules/ansi-styles": {
"version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
@@ -24197,8 +23938,9 @@
},
"node_modules/electron-publish/node_modules/chalk": {
"version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ansi-styles": "^4.1.0",
"supports-color": "^7.1.0"
@@ -24212,8 +23954,9 @@
},
"node_modules/electron-publish/node_modules/color-convert": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
@@ -24223,13 +23966,15 @@
},
"node_modules/electron-publish/node_modules/color-name": {
"version": "1.1.4",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
},
"node_modules/electron-publish/node_modules/fs-extra": {
"version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -24241,16 +23986,18 @@
},
"node_modules/electron-publish/node_modules/has-flag": {
"version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/electron-publish/node_modules/supports-color": {
"version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
"dev": true,
- "license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -24313,6 +24060,15 @@
"node": ">= 0.8"
}
},
+ "node_modules/encoding": {
+ "version": "0.1.13",
+ "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+ "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+ "optional": true,
+ "dependencies": {
+ "iconv-lite": "^0.6.2"
+ }
+ },
"node_modules/end-of-stream": {
"version": "1.4.4",
"license": "MIT",
@@ -26003,9 +25759,9 @@
}
},
"node_modules/expensify-common": {
- "version": "2.0.39",
- "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.39.tgz",
- "integrity": "sha512-HyW7MiS8+ZWO2xye5TSsiKJfIsaGl0M2RlI+txJNF9GWeroA6kaXybTY1Ppq+cS+a7+MU/KMQh7GNnIMrvkf+w==",
+ "version": "2.0.49",
+ "resolved": "https://registry.npmjs.org/expensify-common/-/expensify-common-2.0.49.tgz",
+ "integrity": "sha512-67QbRuR2XEl2RoNLSbyqGWATIbOXPV42azAfs2sqNT6iyWKcOgHUqRkWPhxA0GmSW35lwq66bvgPVsQUfMGCow==",
"dependencies": {
"awesome-phonenumber": "^5.4.0",
"classnames": "2.5.0",
@@ -26019,7 +25775,7 @@
"react-dom": "16.12.0",
"semver": "^7.6.2",
"simply-deferred": "git+https://github.com/Expensify/simply-deferred.git#77a08a95754660c7bd6e0b6979fdf84e8e831bf5",
- "ua-parser-js": "^1.0.37"
+ "ua-parser-js": "^1.0.38"
}
},
"node_modules/expensify-common/node_modules/react": {
@@ -26056,9 +25812,9 @@
}
},
"node_modules/expensify-common/node_modules/ua-parser-js": {
- "version": "1.0.37",
- "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz",
- "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==",
+ "version": "1.0.38",
+ "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.38.tgz",
+ "integrity": "sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==",
"funding": [
{
"type": "opencollective",
@@ -26381,6 +26137,12 @@
"node": ">=8"
}
},
+ "node_modules/exponential-backoff": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz",
+ "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==",
+ "dev": true
+ },
"node_modules/express": {
"version": "4.18.1",
"license": "MIT",
@@ -26544,11 +26306,12 @@
},
"node_modules/extsprintf": {
"version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz",
+ "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==",
"dev": true,
"engines": [
"node >=0.6.0"
],
- "license": "MIT",
"optional": true
},
"node_modules/fast-deep-equal": {
@@ -27797,8 +27560,8 @@
},
"node_modules/has-unicode": {
"version": "2.0.1",
- "license": "ISC",
- "optional": true
+ "devOptional": true,
+ "license": "ISC"
},
"node_modules/has-value": {
"version": "1.0.0",
@@ -28024,8 +27787,9 @@
},
"node_modules/hosted-git-info": {
"version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+ "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
"dev": true,
- "license": "ISC",
"dependencies": {
"lru-cache": "^6.0.0"
},
@@ -28285,6 +28049,15 @@
"node": ">=10.17.0"
}
},
+ "node_modules/humanize-ms": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+ "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+ "dev": true,
+ "dependencies": {
+ "ms": "^2.0.0"
+ }
+ },
"node_modules/husky": {
"version": "1.3.1",
"dev": true,
@@ -28560,8 +28333,9 @@
},
"node_modules/iconv-corefoundation": {
"version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz",
+ "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==",
"dev": true,
- "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -28930,6 +28704,25 @@
"node": ">=0.10.0"
}
},
+ "node_modules/ip-address": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
+ "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
+ "dev": true,
+ "dependencies": {
+ "jsbn": "1.1.0",
+ "sprintf-js": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/ip-address/node_modules/sprintf-js": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
+ "dev": true
+ },
"node_modules/ip-regex": {
"version": "2.1.0",
"license": "MIT",
@@ -29077,8 +28870,9 @@
},
"node_modules/is-ci": {
"version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz",
+ "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"ci-info": "^3.2.0"
},
@@ -29313,6 +29107,12 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-lambda": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
+ "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
+ "dev": true
+ },
"node_modules/is-map": {
"version": "2.0.2",
"dev": true,
@@ -29589,8 +29389,9 @@
},
"node_modules/isbinaryfile": {
"version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.2.tgz",
+ "integrity": "sha512-GvcjojwonMjWbTkfMpnVHVqXW/wKMYDfEpY94/8zy8HFMOqb/VL6oeONq9v87q4ttVlaTLnGXnJD4B5B1OTGIg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 18.0.0"
},
@@ -29887,28 +29688,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-circus/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-circus/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-circus/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -29999,28 +29778,6 @@
}
}
},
- "node_modules/jest-cli/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-cli/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-cli/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -30122,28 +29879,6 @@
}
}
},
- "node_modules/jest-config/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-config/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-config/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -30297,28 +30032,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-each/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-each/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-each/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -30402,28 +30115,6 @@
}
}
},
- "node_modules/jest-environment-jsdom/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-environment-jsdom/node_modules/acorn": {
"version": "8.11.3",
"license": "MIT",
@@ -30434,47 +30125,6 @@
"node": ">=0.4.0"
}
},
- "node_modules/jest-environment-jsdom/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-environment-jsdom/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
"node_modules/jest-environment-jsdom/node_modules/cssstyle": {
"version": "2.3.0",
"license": "MIT",
@@ -30523,13 +30173,6 @@
"node": ">= 6"
}
},
- "node_modules/jest-environment-jsdom/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/jest-environment-jsdom/node_modules/html-encoding-sniffer": {
"version": "3.0.0",
"license": "MIT",
@@ -30593,16 +30236,6 @@
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
- "node_modules/jest-environment-jsdom/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/jest-environment-jsdom/node_modules/tr46": {
"version": "3.0.0",
"license": "MIT",
@@ -30673,86 +30306,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-environment-node/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-environment-node/node_modules/@types/yargs": {
- "version": "17.0.31",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/jest-environment-node/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-environment-node/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-environment-node/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-environment-node/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/jest-environment-node/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-environment-node/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/jest-expo": {
"version": "50.0.1",
"license": "MIT",
@@ -30820,69 +30373,6 @@
"fsevents": "^2.3.2"
}
},
- "node_modules/jest-haste-map/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-haste-map/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/jest-haste-map/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-haste-map/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-haste-map/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-haste-map/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
"node_modules/jest-haste-map/node_modules/has-flag": {
"version": "4.0.0",
"license": "MIT",
@@ -30916,16 +30406,6 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
- "node_modules/jest-haste-map/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/jest-leak-detector": {
"version": "29.4.1",
"license": "MIT",
@@ -31026,28 +30506,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-message-util/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-message-util/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-message-util/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -31118,86 +30576,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-mock/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-mock/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/jest-mock/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest-mock/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest-mock/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest-mock/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/jest-mock/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest-mock/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/jest-pnp-resolver": {
"version": "1.2.3",
"license": "MIT",
@@ -31337,28 +30715,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-runner/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-runner/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-runner/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -31483,28 +30839,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-runtime/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-runtime/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-runtime/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -31592,28 +30926,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-snapshot/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-snapshot/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-snapshot/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -31696,28 +31008,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-util/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-util/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-util/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -31791,28 +31081,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-validate/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-validate/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-validate/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -32106,28 +31374,6 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
- "node_modules/jest-watcher/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest-watcher/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
"node_modules/jest-watcher/node_modules/ansi-styles": {
"version": "4.3.0",
"license": "MIT",
@@ -32228,86 +31474,6 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
- "node_modules/jest/node_modules/@jest/types": {
- "version": "29.6.3",
- "license": "MIT",
- "dependencies": {
- "@jest/schemas": "^29.6.3",
- "@types/istanbul-lib-coverage": "^2.0.0",
- "@types/istanbul-reports": "^3.0.0",
- "@types/node": "*",
- "@types/yargs": "^17.0.8",
- "chalk": "^4.0.0"
- },
- "engines": {
- "node": "^14.15.0 || ^16.10.0 || >=18.0.0"
- }
- },
- "node_modules/jest/node_modules/@types/yargs": {
- "version": "17.0.24",
- "license": "MIT",
- "dependencies": {
- "@types/yargs-parser": "*"
- }
- },
- "node_modules/jest/node_modules/ansi-styles": {
- "version": "4.3.0",
- "license": "MIT",
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/jest/node_modules/chalk": {
- "version": "4.1.2",
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/jest/node_modules/color-convert": {
- "version": "2.0.1",
- "license": "MIT",
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/jest/node_modules/color-name": {
- "version": "1.1.4",
- "license": "MIT"
- },
- "node_modules/jest/node_modules/has-flag": {
- "version": "4.0.0",
- "license": "MIT",
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/jest/node_modules/supports-color": {
- "version": "7.2.0",
- "license": "MIT",
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/jimp-compact": {
"version": "0.16.1",
"license": "MIT"
@@ -32359,6 +31525,12 @@
"js-yaml": "bin/js-yaml.js"
}
},
+ "node_modules/jsbn": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
+ "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
+ "dev": true
+ },
"node_modules/jsc-android": {
"version": "250231.0.0",
"license": "BSD-2-Clause"
@@ -32707,13 +31879,15 @@
},
"node_modules/lazy-val": {
"version": "1.0.5",
- "dev": true,
- "license": "MIT"
+ "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz",
+ "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==",
+ "dev": true
},
"node_modules/lazystream": {
"version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"readable-stream": "^2.0.5"
@@ -32932,20 +32106,23 @@
},
"node_modules/lodash.defaults": {
"version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"dev": true,
- "license": "MIT",
"peer": true
},
"node_modules/lodash.difference": {
"version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
+ "integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==",
"dev": true,
- "license": "MIT",
"peer": true
},
"node_modules/lodash.flatten": {
"version": "4.4.0",
+ "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+ "integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
"dev": true,
- "license": "MIT",
"peer": true
},
"node_modules/lodash.isequal": {
@@ -32954,8 +32131,9 @@
},
"node_modules/lodash.isplainobject": {
"version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+ "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"dev": true,
- "license": "MIT",
"peer": true
},
"node_modules/lodash.memoize": {
@@ -32975,8 +32153,9 @@
},
"node_modules/lodash.union": {
"version": "4.6.0",
+ "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
+ "integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==",
"dev": true,
- "license": "MIT",
"peer": true
},
"node_modules/log-symbols": {
@@ -33344,6 +32523,175 @@
"url": "https://github.com/wojtekmaj/make-event-props?sponsor=1"
}
},
+ "node_modules/make-fetch-happen": {
+ "version": "10.2.1",
+ "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz",
+ "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==",
+ "dev": true,
+ "dependencies": {
+ "agentkeepalive": "^4.2.1",
+ "cacache": "^16.1.0",
+ "http-cache-semantics": "^4.1.0",
+ "http-proxy-agent": "^5.0.0",
+ "https-proxy-agent": "^5.0.0",
+ "is-lambda": "^1.0.1",
+ "lru-cache": "^7.7.1",
+ "minipass": "^3.1.6",
+ "minipass-collect": "^1.0.2",
+ "minipass-fetch": "^2.0.3",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.4",
+ "negotiator": "^0.6.3",
+ "promise-retry": "^2.0.1",
+ "socks-proxy-agent": "^7.0.0",
+ "ssri": "^9.0.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/@npmcli/fs": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz",
+ "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==",
+ "dev": true,
+ "dependencies": {
+ "@gar/promisify": "^1.1.3",
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/@npmcli/move-file": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz",
+ "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==",
+ "deprecated": "This functionality has been moved to @npmcli/fs",
+ "dev": true,
+ "dependencies": {
+ "mkdirp": "^1.0.4",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/cacache": {
+ "version": "16.1.3",
+ "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz",
+ "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==",
+ "dev": true,
+ "dependencies": {
+ "@npmcli/fs": "^2.1.0",
+ "@npmcli/move-file": "^2.0.0",
+ "chownr": "^2.0.0",
+ "fs-minipass": "^2.1.0",
+ "glob": "^8.0.1",
+ "infer-owner": "^1.0.4",
+ "lru-cache": "^7.7.1",
+ "minipass": "^3.1.6",
+ "minipass-collect": "^1.0.2",
+ "minipass-flush": "^1.0.5",
+ "minipass-pipeline": "^1.2.4",
+ "mkdirp": "^1.0.4",
+ "p-map": "^4.0.0",
+ "promise-inflight": "^1.0.1",
+ "rimraf": "^3.0.2",
+ "ssri": "^9.0.0",
+ "tar": "^6.1.11",
+ "unique-filename": "^2.0.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/lru-cache": {
+ "version": "7.18.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
+ "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/ssri": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz",
+ "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/unique-filename": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz",
+ "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==",
+ "dev": true,
+ "dependencies": {
+ "unique-slug": "^3.0.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/make-fetch-happen/node_modules/unique-slug": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz",
+ "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==",
+ "dev": true,
+ "dependencies": {
+ "imurmurhash": "^0.1.4"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
"node_modules/makeerror": {
"version": "1.0.12",
"license": "BSD-3-Clause",
@@ -34101,8 +33449,9 @@
}
},
"node_modules/metro/node_modules/ws": {
- "version": "7.5.9",
- "license": "MIT",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"engines": {
"node": ">=8.3.0"
},
@@ -34240,6 +33589,23 @@
"node": ">= 8"
}
},
+ "node_modules/minipass-fetch": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz",
+ "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.1.6",
+ "minipass-sized": "^1.0.3",
+ "minizlib": "^2.1.2"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ },
+ "optionalDependencies": {
+ "encoding": "^0.1.13"
+ }
+ },
"node_modules/minipass-flush": {
"version": "1.0.5",
"license": "ISC",
@@ -34260,6 +33626,18 @@
"node": ">=8"
}
},
+ "node_modules/minipass-sized": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
+ "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/minizlib": {
"version": "2.1.2",
"license": "MIT",
@@ -34516,16 +33894,38 @@
"node": ">= 10.13"
}
},
+ "node_modules/node-abi": {
+ "version": "3.65.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.65.0.tgz",
+ "integrity": "sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.3.5"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/node-abort-controller": {
"version": "3.1.1",
"license": "MIT"
},
"node_modules/node-addon-api": {
"version": "1.7.2",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz",
+ "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==",
"dev": true,
- "license": "MIT",
"optional": true
},
+ "node_modules/node-api-version": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.0.tgz",
+ "integrity": "sha512-fthTTsi8CxaBXMaBAD7ST2uylwvsnYxh2PfaScwpMhos6KlSFajXQPcM4ogNE1q2s3Lbz9GCGqeIHC+C6OZnKg==",
+ "dev": true,
+ "dependencies": {
+ "semver": "^7.3.5"
+ }
+ },
"node_modules/node-dir": {
"version": "0.1.17",
"license": "MIT",
@@ -34583,6 +33983,95 @@
"node": ">= 6.13.0"
}
},
+ "node_modules/node-gyp": {
+ "version": "9.4.1",
+ "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.1.tgz",
+ "integrity": "sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==",
+ "dev": true,
+ "dependencies": {
+ "env-paths": "^2.2.0",
+ "exponential-backoff": "^3.1.1",
+ "glob": "^7.1.4",
+ "graceful-fs": "^4.2.6",
+ "make-fetch-happen": "^10.0.3",
+ "nopt": "^6.0.0",
+ "npmlog": "^6.0.0",
+ "rimraf": "^3.0.2",
+ "semver": "^7.3.5",
+ "tar": "^6.1.2",
+ "which": "^2.0.2"
+ },
+ "bin": {
+ "node-gyp": "bin/node-gyp.js"
+ },
+ "engines": {
+ "node": "^12.13 || ^14.13 || >=16"
+ }
+ },
+ "node_modules/node-gyp/node_modules/are-we-there-yet": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz",
+ "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==",
+ "deprecated": "This package is no longer supported.",
+ "dev": true,
+ "dependencies": {
+ "delegates": "^1.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/gauge": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz",
+ "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==",
+ "deprecated": "This package is no longer supported.",
+ "dev": true,
+ "dependencies": {
+ "aproba": "^1.0.3 || ^2.0.0",
+ "color-support": "^1.1.3",
+ "console-control-strings": "^1.1.0",
+ "has-unicode": "^2.0.1",
+ "signal-exit": "^3.0.7",
+ "string-width": "^4.2.3",
+ "strip-ansi": "^6.0.1",
+ "wide-align": "^1.1.5"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/npmlog": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz",
+ "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==",
+ "deprecated": "This package is no longer supported.",
+ "dev": true,
+ "dependencies": {
+ "are-we-there-yet": "^3.0.0",
+ "console-control-strings": "^1.1.0",
+ "gauge": "^4.0.3",
+ "set-blocking": "^2.0.0"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
+ "node_modules/node-gyp/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/node-int64": {
"version": "0.4.0",
"license": "MIT"
@@ -34650,6 +34139,21 @@
"url": "https://github.com/sponsors/antelle"
}
},
+ "node_modules/nopt": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz",
+ "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==",
+ "dev": true,
+ "dependencies": {
+ "abbrev": "^1.0.0"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
+ }
+ },
"node_modules/normalize-package-data": {
"version": "2.5.0",
"license": "BSD-2-Clause",
@@ -35876,6 +35380,16 @@
"path2d-polyfill": "^2.0.1"
}
},
+ "node_modules/pe-library": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.0.tgz",
+ "integrity": "sha512-JAmVv2jGxmczplhHO7UoFGJ+pM/yMBpny3vNjwNFuaeQfzKlekQidZ8Ss8EJ0qee8wEQN4lY2IwtWx2oRfMsag==",
+ "dev": true,
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
"node_modules/peek-stream": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz",
@@ -36045,14 +35559,24 @@
}
},
"node_modules/plist": {
- "version": "3.0.6",
- "license": "MIT",
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz",
+ "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==",
"dependencies": {
+ "@xmldom/xmldom": "^0.8.8",
"base64-js": "^1.5.1",
"xmlbuilder": "^15.1.1"
},
"engines": {
- "node": ">=6"
+ "node": ">=10.4.0"
+ }
+ },
+ "node_modules/plist/node_modules/@xmldom/xmldom": {
+ "version": "0.8.10",
+ "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
+ "integrity": "sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==",
+ "engines": {
+ "node": ">=10.0.0"
}
},
"node_modules/plist/node_modules/xmlbuilder": {
@@ -37461,9 +36985,9 @@
}
},
"node_modules/react-native-pager-view": {
- "version": "6.2.3",
- "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.2.3.tgz",
- "integrity": "sha512-dqVpXWFtPNfD3D2QQQr8BP+ullS5MhjRJuF8Z/qml4QTILcrWaW8F5iAxKkQR3Jl0ikcEryG/+SQlNcwlo0Ggg==",
+ "version": "6.3.3",
+ "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.3.3.tgz",
+ "integrity": "sha512-HViKBlfN/kBJUSu5mRL/V9Bkf1j7uDZozGAjbzh4o9XYo11qVcIK7IwvfzqrkNerVSDy/cAmZcXbcyWnII8xMA==",
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -37517,17 +37041,17 @@
}
},
"node_modules/react-native-plaid-link-sdk": {
- "version": "11.5.0",
- "resolved": "https://registry.npmjs.org/react-native-plaid-link-sdk/-/react-native-plaid-link-sdk-11.5.0.tgz",
- "integrity": "sha512-B3fwujxBS9nZwadXFcseU3nrYG7Ptob6p9eG/gXde65cqwErMaq2k1rVv3R17s/rpKnmU5Cx5pKOMmkxPUn08w==",
+ "version": "11.11.0",
+ "resolved": "https://registry.npmjs.org/react-native-plaid-link-sdk/-/react-native-plaid-link-sdk-11.11.0.tgz",
+ "integrity": "sha512-Kmimhr6iOwCtIzsW7gygz48TzaZsdjnpgstJ2PM1q+THulOnx+BnkFu8UpLIGGkVe19E4wkxOAYL8kJ8vefNSQ==",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-qrcode-svg": {
- "version": "6.2.0",
- "license": "MIT",
+ "version": "6.3.0",
+ "resolved": "git+ssh://git@github.com/Expensify/react-native-qrcode-svg.git#295f87d45c0f10d9b50838ad28fa70e47d054c3b",
"dependencies": {
"prop-types": "^15.8.0",
"qrcode": "^1.5.1"
@@ -37535,7 +37059,7 @@
"peerDependencies": {
"react": "*",
"react-native": ">=0.63.4",
- "react-native-svg": "^13.2.0"
+ "react-native-svg": ">=13.2.0"
}
},
"node_modules/react-native-quick-sqlite": {
@@ -37578,14 +37102,15 @@
"license": "MIT"
},
"node_modules/react-native-release-profiler": {
- "version": "0.1.6",
- "license": "MIT",
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/react-native-release-profiler/-/react-native-release-profiler-0.2.1.tgz",
+ "integrity": "sha512-gDOwEXypd4Gu++nlKyaVLHPfwrVkkdBrsjMrQORYTTDqcrD/OfuNZ8YK7p+u5LUNjnPD4WmBF88C5dEW7iM1lg==",
"workspaces": [
"example"
],
"dependencies": {
- "@react-native-community/cli": "^12.2.1",
- "commander": "^11.1.0"
+ "commander": "^11.1.0",
+ "hermes-profile-transformer": "^0.0.9"
},
"bin": {
"react-native-release-profiler": "lib/commonjs/cli.js"
@@ -37605,6 +37130,25 @@
"node": ">=16"
}
},
+ "node_modules/react-native-release-profiler/node_modules/hermes-profile-transformer": {
+ "version": "0.0.9",
+ "resolved": "https://registry.npmjs.org/hermes-profile-transformer/-/hermes-profile-transformer-0.0.9.tgz",
+ "integrity": "sha512-JYPUE9zA+W/hpTIGBV+t2ODvntataLLMfntoEcpEpKFDwdR6+Quk9SwLnWX9y2A3ZII6N4T8w3TUBC2ejsEGBw==",
+ "dependencies": {
+ "source-map": "^0.7.3"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/react-native-release-profiler/node_modules/source-map": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+ "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/react-native-render-html": {
"version": "6.3.1",
"license": "BSD-2-Clause",
@@ -37682,11 +37226,13 @@
}
},
"node_modules/react-native-svg": {
- "version": "14.1.0",
- "license": "MIT",
+ "version": "15.4.0",
+ "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.4.0.tgz",
+ "integrity": "sha512-zkBEbme/Dba4yqreg/oI2P6/6LrLywWY7HhaSwpU7Pb5COpTd2fV6/ShsgZz8GRFFdidUPwWmx01FITUsjhkmw==",
"dependencies": {
"css-select": "^5.1.0",
- "css-tree": "^1.1.3"
+ "css-tree": "^1.1.3",
+ "warn-once": "0.1.1"
},
"peerDependencies": {
"react": "*",
@@ -37958,8 +37504,9 @@
}
},
"node_modules/react-native/node_modules/ws": {
- "version": "6.2.2",
- "license": "MIT",
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz",
+ "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==",
"dependencies": {
"async-limiter": "~1.0.0"
}
@@ -38133,10 +37680,6 @@
"react": "^18.2.0"
}
},
- "node_modules/react-test-renderer/node_modules/react-is": {
- "version": "18.2.0",
- "license": "MIT"
- },
"node_modules/react-test-renderer/node_modules/scheduler": {
"version": "0.23.0",
"license": "MIT",
@@ -38565,6 +38108,18 @@
"react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0"
}
},
+ "node_modules/read-binary-file-arch": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz",
+ "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==",
+ "dev": true,
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "bin": {
+ "read-binary-file-arch": "cli.js"
+ }
+ },
"node_modules/read-cmd-shim": {
"version": "4.0.0",
"license": "ISC",
@@ -38573,16 +38128,17 @@
}
},
"node_modules/read-config-file": {
- "version": "6.3.2",
+ "version": "6.4.0",
+ "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.4.0.tgz",
+ "integrity": "sha512-uB5QOBeF84PT61GlV11OTV4jUGHAO3iDEOP6v9ygxhG6Bs9PLg7WsjNT6mtIX2G+x8lJTr4ZWNeG6LDTKkNf2Q==",
"dev": true,
- "license": "MIT",
"dependencies": {
- "config-file-ts": "^0.2.4",
- "dotenv": "^9.0.2",
- "dotenv-expand": "^5.1.0",
+ "config-file-ts": "0.2.8-rc1",
+ "dotenv": "^16.4.5",
+ "dotenv-expand": "^11.0.6",
"js-yaml": "^4.1.0",
- "json5": "^2.2.0",
- "lazy-val": "^1.0.4"
+ "json5": "^2.2.3",
+ "lazy-val": "^1.0.5"
},
"engines": {
"node": ">=12.0.0"
@@ -38590,21 +38146,15 @@
},
"node_modules/read-config-file/node_modules/argparse": {
"version": "2.0.1",
- "dev": true,
- "license": "Python-2.0"
- },
- "node_modules/read-config-file/node_modules/dotenv": {
- "version": "9.0.2",
- "dev": true,
- "license": "BSD-2-Clause",
- "engines": {
- "node": ">=10"
- }
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
+ "dev": true
},
"node_modules/read-config-file/node_modules/js-yaml": {
"version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+ "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"dev": true,
- "license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
@@ -38775,8 +38325,9 @@
},
"node_modules/readdir-glob": {
"version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
"dev": true,
- "license": "Apache-2.0",
"peer": true,
"dependencies": {
"minimatch": "^5.1.0"
@@ -38784,8 +38335,9 @@
},
"node_modules/readdir-glob/node_modules/brace-expansion": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"balanced-match": "^1.0.0"
@@ -38793,8 +38345,9 @@
},
"node_modules/readdir-glob/node_modules/minimatch": {
"version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
- "license": "ISC",
"peer": true,
"dependencies": {
"brace-expansion": "^2.0.1"
@@ -39160,6 +38713,19 @@
"version": "1.0.0",
"license": "MIT"
},
+ "node_modules/resedit": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.0.tgz",
+ "integrity": "sha512-dbsZ0gk5opWPFlKMqvxCrLCuMZUVmsW3yTPT0tT4mYwo5fjQM8c4HMN9ZJt6dRDqDV/78m9SU4rv24PN4NiYaA==",
+ "dev": true,
+ "dependencies": {
+ "pe-library": "^0.4.0"
+ },
+ "engines": {
+ "node": ">=12",
+ "npm": ">=6"
+ }
+ },
"node_modules/reselect": {
"version": "4.1.7",
"dev": true,
@@ -39432,8 +38998,9 @@
},
"node_modules/sanitize-filename": {
"version": "1.6.3",
+ "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
+ "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
"dev": true,
- "license": "WTFPL OR ISC",
"dependencies": {
"truncate-utf8-bytes": "^1.0.0"
}
@@ -39973,8 +39540,9 @@
},
"node_modules/slice-ansi": {
"version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz",
+ "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"ansi-styles": "^4.0.0",
@@ -39987,8 +39555,9 @@
},
"node_modules/slice-ansi/node_modules/ansi-styles": {
"version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"color-convert": "^2.0.1"
@@ -40002,8 +39571,9 @@
},
"node_modules/slice-ansi/node_modules/color-convert": {
"version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"color-name": "~1.1.4"
@@ -40014,8 +39584,9 @@
},
"node_modules/slice-ansi/node_modules/color-name": {
"version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
- "license": "MIT",
"optional": true
},
"node_modules/slugify": {
@@ -40027,9 +39598,9 @@
},
"node_modules/smart-buffer": {
"version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+ "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
"dev": true,
- "license": "MIT",
- "optional": true,
"engines": {
"node": ">= 6.0.0",
"npm": ">= 3.0.0"
@@ -40235,6 +39806,34 @@
"websocket-driver": "^0.7.4"
}
},
+ "node_modules/socks": {
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
+ "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==",
+ "dev": true,
+ "dependencies": {
+ "ip-address": "^9.0.5",
+ "smart-buffer": "^4.2.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0",
+ "npm": ">= 3.0.0"
+ }
+ },
+ "node_modules/socks-proxy-agent": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz",
+ "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==",
+ "dev": true,
+ "dependencies": {
+ "agent-base": "^6.0.2",
+ "debug": "^4.3.3",
+ "socks": "^2.6.2"
+ },
+ "engines": {
+ "node": ">= 10"
+ }
+ },
"node_modules/sort-asc": {
"version": "0.2.0",
"license": "MIT",
@@ -40521,8 +40120,9 @@
},
"node_modules/stat-mode": {
"version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz",
+ "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">= 6"
}
@@ -41263,8 +40863,9 @@
},
"node_modules/temp-file": {
"version": "3.4.0",
+ "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz",
+ "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"async-exit-hook": "^2.0.1",
"fs-extra": "^10.0.0"
@@ -41272,8 +40873,9 @@
},
"node_modules/temp-file/node_modules/fs-extra": {
"version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+ "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -41615,16 +41217,18 @@
},
"node_modules/tmp": {
"version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz",
+ "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=14.14"
}
},
"node_modules/tmp-promise": {
"version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz",
+ "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==",
"dev": true,
- "license": "MIT",
"dependencies": {
"tmp": "^0.2.0"
}
@@ -41765,8 +41369,9 @@
},
"node_modules/truncate-utf8-bytes": {
"version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
+ "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==",
"dev": true,
- "license": "WTFPL",
"dependencies": {
"utf8-byte-length": "^1.0.1"
}
@@ -42571,9 +42176,10 @@
"license": "MIT"
},
"node_modules/utf8-byte-length": {
- "version": "1.0.4",
- "dev": true,
- "license": "WTFPL"
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz",
+ "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==",
+ "dev": true
},
"node_modules/util": {
"version": "0.11.1",
@@ -42659,8 +42265,9 @@
},
"node_modules/verror": {
"version": "1.10.1",
+ "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz",
+ "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==",
"dev": true,
- "license": "MIT",
"optional": true,
"dependencies": {
"assert-plus": "^1.0.0",
@@ -43163,9 +42770,10 @@
}
},
"node_modules/webpack-bundle-analyzer/node_modules/ws": {
- "version": "7.5.9",
+ "version": "7.5.10",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
+ "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==",
"dev": true,
- "license": "MIT",
"engines": {
"node": ">=8.3.0"
},
@@ -43788,8 +43396,8 @@
},
"node_modules/wide-align": {
"version": "1.1.5",
+ "devOptional": true,
"license": "ISC",
- "optional": true,
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
@@ -43927,8 +43535,9 @@
}
},
"node_modules/ws": {
- "version": "8.16.0",
- "license": "MIT",
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
"engines": {
"node": ">=10.0.0"
},
@@ -44076,8 +43685,9 @@
},
"node_modules/zip-stream": {
"version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz",
+ "integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"archiver-utils": "^3.0.4",
@@ -44090,8 +43700,9 @@
},
"node_modules/zip-stream/node_modules/archiver-utils": {
"version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-3.0.4.tgz",
+ "integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"glob": "^7.2.3",
@@ -44111,8 +43722,10 @@
},
"node_modules/zip-stream/node_modules/glob": {
"version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
- "license": "ISC",
"peer": true,
"dependencies": {
"fs.realpath": "^1.0.0",
@@ -44131,8 +43744,9 @@
},
"node_modules/zip-stream/node_modules/readable-stream": {
"version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
"dev": true,
- "license": "MIT",
"peer": true,
"dependencies": {
"inherits": "^2.0.3",
diff --git a/package.json b/package.json
index 02b8ce22cd20..81e963e12671 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "9.0.8-2",
+ "version": "9.0.9-1",
"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.",
@@ -68,7 +68,7 @@
"@babel/plugin-proposal-private-methods": "^7.18.6",
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"@dotlottie/react-player": "^1.6.3",
- "@expensify/react-native-live-markdown": "0.1.103",
+ "@expensify/react-native-live-markdown": "0.1.105",
"@expo/metro-runtime": "~3.1.1",
"@formatjs/intl-datetimeformat": "^6.10.0",
"@formatjs/intl-listformat": "^7.2.2",
@@ -86,7 +86,7 @@
"@onfido/react-native-sdk": "10.6.0",
"@react-native-camera-roll/camera-roll": "7.4.0",
"@react-native-clipboard/clipboard": "^1.13.2",
- "@react-native-community/geolocation": "3.2.1",
+ "@react-native-community/geolocation": "3.3.0",
"@react-native-community/netinfo": "11.2.1",
"@react-native-firebase/analytics": "^12.3.0",
"@react-native-firebase/app": "^12.3.0",
@@ -110,7 +110,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "2.0.39",
+ "expensify-common": "2.0.49",
"expo": "^50.0.3",
"expo-av": "~13.10.4",
"expo-image": "1.11.0",
@@ -158,22 +158,22 @@
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
"react-native-onyx": "2.0.56",
- "react-native-pager-view": "6.2.3",
+ "react-native-pager-view": "6.3.3",
"react-native-pdf": "6.7.3",
"react-native-performance": "^5.1.0",
"react-native-permissions": "^3.10.0",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#da50d2c5c54e268499047f9cc98b8df4196c1ddf",
- "react-native-plaid-link-sdk": "11.5.0",
- "react-native-qrcode-svg": "^6.2.0",
+ "react-native-plaid-link-sdk": "11.11.0",
+ "react-native-qrcode-svg": "git+https://github.com/Expensify/react-native-qrcode-svg",
"react-native-quick-sqlite": "git+https://github.com/margelo/react-native-quick-sqlite#abc91857d4b3efb2020ec43abd2a508563b64316",
"react-native-reanimated": "^3.8.0",
- "react-native-release-profiler": "^0.1.6",
+ "react-native-release-profiler": "^0.2.1",
"react-native-render-html": "6.3.1",
"react-native-safe-area-context": "4.8.2",
"react-native-screens": "3.32.0",
"react-native-share": "^10.0.2",
"react-native-sound": "^0.11.2",
- "react-native-svg": "14.1.0",
+ "react-native-svg": "15.4.0",
"react-native-tab-view": "^3.5.2",
"react-native-url-polyfill": "^2.0.0",
"react-native-view-shot": "3.8.0",
@@ -210,7 +210,7 @@
"@octokit/core": "4.0.4",
"@octokit/plugin-paginate-rest": "3.1.0",
"@octokit/plugin-throttling": "4.1.0",
- "@perf-profiler/profiler": "^0.10.10",
+ "@perf-profiler/profiler": "^0.10.11",
"@perf-profiler/reporter": "^0.9.0",
"@perf-profiler/types": "^0.8.0",
"@react-native-community/eslint-config": "3.2.0",
@@ -267,7 +267,7 @@
"diff-so-fancy": "^1.3.0",
"dotenv": "^16.0.3",
"electron": "^29.4.1",
- "electron-builder": "24.13.2",
+ "electron-builder": "25.0.0",
"eslint": "^8.57.0",
"eslint-config-airbnb-typescript": "^18.0.0",
"eslint-config-expensify": "^2.0.52",
diff --git a/patches/@perf-profiler+android+0.12.1.patch b/patches/@perf-profiler+android+0.12.1.patch
deleted file mode 100644
index e6e4a90d6ab4..000000000000
--- a/patches/@perf-profiler+android+0.12.1.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-diff --git a/node_modules/@perf-profiler/android/dist/src/commands/platforms/UnixProfiler.js b/node_modules/@perf-profiler/android/dist/src/commands/platforms/UnixProfiler.js
-index 59aeed9..ee1d8a6 100644
---- a/node_modules/@perf-profiler/android/dist/src/commands/platforms/UnixProfiler.js
-+++ b/node_modules/@perf-profiler/android/dist/src/commands/platforms/UnixProfiler.js
-@@ -28,7 +28,7 @@ exports.CppProfilerName = `BAMPerfProfiler`;
- // into the Flipper plugin directory
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-expect-error
--const binaryFolder = global.Flipper
-+const binaryFolder = (global.Flipper || process.env.AWS)
- ? `${__dirname}/bin`
- : `${__dirname}/../../..${__dirname.includes("dist") ? "/.." : ""}/cpp-profiler/bin`;
- class UnixProfiler {
-diff --git a/node_modules/@perf-profiler/android/src/commands/platforms/UnixProfiler.ts b/node_modules/@perf-profiler/android/src/commands/platforms/UnixProfiler.ts
-index ccacf09..1eea659 100644
---- a/node_modules/@perf-profiler/android/src/commands/platforms/UnixProfiler.ts
-+++ b/node_modules/@perf-profiler/android/src/commands/platforms/UnixProfiler.ts
-@@ -26,7 +26,7 @@ export const CppProfilerName = `BAMPerfProfiler`;
- // into the Flipper plugin directory
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
- // @ts-expect-error
--const binaryFolder = global.Flipper
-+const binaryFolder = (global.Flipper || process.env.AWS)
- ? `${__dirname}/bin`
- : `${__dirname}/../../..${__dirname.includes("dist") ? "/.." : ""}/cpp-profiler/bin`;
-
diff --git a/patches/react-native-plaid-link-sdk+11.5.0+001+initial.patch b/patches/react-native-plaid-link-sdk+11.5.0+001+initial.patch
deleted file mode 100644
index 6035477256b7..000000000000
--- a/patches/react-native-plaid-link-sdk+11.5.0+001+initial.patch
+++ /dev/null
@@ -1,4 +0,0 @@
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.m b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.mm
-similarity index 100%
-rename from node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.m
-rename to node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.mm
diff --git a/patches/react-native-plaid-link-sdk+11.5.0+002+turbomodule.patch b/patches/react-native-plaid-link-sdk+11.5.0+002+turbomodule.patch
deleted file mode 100644
index 7d5aab6c84cf..000000000000
--- a/patches/react-native-plaid-link-sdk+11.5.0+002+turbomodule.patch
+++ /dev/null
@@ -1,3287 +0,0 @@
-diff --git a/node_modules/react-native-plaid-link-sdk/README.md b/node_modules/react-native-plaid-link-sdk/README.md
-index 93ebca6..7bea608 100644
---- a/node_modules/react-native-plaid-link-sdk/README.md
-+++ b/node_modules/react-native-plaid-link-sdk/README.md
-@@ -49,7 +49,6 @@ cd ios && bundle install && bundle exec pod install
-
- AutoLinking should handle all of the Android setup.
-
--
- ### React Native Setup
-
- - To initialize `PlaidLink`, you will need to first create a `link_token` at [/link/token/create](https://plaid.com/docs/#create-link-token). Check out our [QuickStart guide](https://plaid.com/docs/quickstart/#introduction) for additional API information.
-@@ -58,7 +57,13 @@ AutoLinking should handle all of the Android setup.
-
- ```javascript
- import { Text } from 'react-native';
--import { PlaidLink, LinkSuccess, LinkExit, LinkLogLevel, LinkIOSPresentationStyle } from 'react-native-plaid-link-sdk';
-+import {
-+ PlaidLink,
-+ LinkSuccess,
-+ LinkExit,
-+ LinkLogLevel,
-+ LinkIOSPresentationStyle,
-+} from 'react-native-plaid-link-sdk';
-
- const MyPlaidComponent = () => {
- return (
-@@ -77,7 +82,7 @@ const MyPlaidComponent = () => {
- // UI is always presented in full screen on Android.
- iOSPresentationStyle={LinkIOSPresentationStyle.MODAL}
- >
-- Add Account
-+ Add Account
-
- );
- };
-@@ -92,6 +97,7 @@ const MyPlaidComponent = () => {
- ##### Android OAuth Requirements
-
- ###### Register your app package name
-+
- 1. Log into your [Plaid Dashboard](https://dashboard.plaid.com/developers/api) and navigate to the API page under the Developers tab.
- 2. Next to Allowed Android package names click "Configure" then "Add New Android Package Name".
- 3. Enter your package name, for example `com.plaid.example`.
-@@ -100,17 +106,16 @@ const MyPlaidComponent = () => {
- ##### iOS OAuth Requirements
-
- For iOS OAuth to work, specific requirements must be met.
-+
- 1. Redirect URIs must be [registered](https://plaid.com/docs/link/ios/#register-your-redirect-uri), and set up as [universal links](https://developer.apple.com/documentation/xcode/supporting-associated-domains).
- 2. Your native iOS application, must be configured with your associated domain. See your iOS [set up universal links](https://plaid.com/docs/link/ios/#set-up-universal-links) for more information.
-
--
- ##### Link Token OAuth Requirements
-
- - On iOS you must configure your `link_token` with a [redirect_uri](https://plaid.com/docs/api/tokens/#link-token-create-request-redirect-uri) to support OAuth. When creating a `link_token` for initializing Link on Android, `android_package_name` must be specified and `redirect_uri` must be left blank.
-
- - On Android you must configure your `link_token` with an [android_package_name](https://plaid.com/docs/api/tokens/#link-token-create-request-android-package-name) to support OAuth. When creating a `link_token` for initializing Link on iOS, `android_package_name` must be left blank and `redirect_uri` should be used instead.
-
--
- #### To receive onEvent callbacks:
-
- The React Native Plaid module emits `onEvent` events throughout the account linking process — see [details here](https://plaid.com/docs/link/react-native/#onevent). To receive these events in your React Native app, wrap the `PlaidLink` react component with the following in order to listen for those events:
-@@ -139,9 +144,9 @@ class PlaidEventContainer extends React.Component {
- You can also use the `usePlaidEmitter` hook in react functional components:
-
- ```javascript
-- usePlaidEmitter((event: LinkEvent) => {
-- console.log(event)
-- })
-+usePlaidEmitter((event: LinkEvent) => {
-+ console.log(event);
-+});
- ```
-
- ## Upgrading
-@@ -165,6 +170,8 @@ While these older versions are expected to continue to work without disruption,
- | 11.0.2 | * | [4.0.0+] | 21 | 33 | >=5.0.0 | 14.0 | Active, supports Xcode 15.0.1 |
- | 11.0.1 | * | [4.0.0+] | 21 | 33 | >=5.0.0 | 14.0 | Active, supports Xcode 15.0.1 |
- | 11.0.0 | * | [4.0.0+] | 21 | 33 | >=5.0.0 | 14.0 | Active, supports Xcode 15.0.1 |
-+| 10.13.0 | >= 0.66.0 | [3.14.3+] | 21 | 33 | >=4.7.2 | 11.0 | Active, supports Xcode 14 |
-+| 10.12.0 | >= 0.66.0 | [3.14.3+] | 21 | 33 | >=4.7.1 | 11.0 | Active, supports Xcode 14 |
- | 10.11.0 | >= 0.66.0 | [3.14.1+] | 21 | 33 | >=4.7.1 | 11.0 | Active, supports Xcode 14 |
- | ~10.10.0~ | >= 0.66.0 | [3.14.2+] | 21 | 33 | >=4.7.1 | 11.0 | **Deprecated** |
- | 10.9.1 | >= 0.66.0 | [3.14.1+] | 21 | 33 | >=4.7.0 | 11.0 | Active, supports Xcode 14 |
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/checksums.lock b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/checksums.lock
-deleted file mode 100644
-index b5da584..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/checksums.lock and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/md5-checksums.bin b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/md5-checksums.bin
-deleted file mode 100644
-index ef608b4..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/md5-checksums.bin and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/sha1-checksums.bin b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/sha1-checksums.bin
-deleted file mode 100644
-index 0856ae4..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/checksums/sha1-checksums.bin and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/dependencies-accessors/dependencies-accessors.lock b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/dependencies-accessors/dependencies-accessors.lock
-deleted file mode 100644
-index 12aea68..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/dependencies-accessors/dependencies-accessors.lock and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/dependencies-accessors/gc.properties b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/dependencies-accessors/gc.properties
-deleted file mode 100644
-index e69de29..0000000
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/fileChanges/last-build.bin b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/fileChanges/last-build.bin
-deleted file mode 100644
-index f76dd23..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/fileChanges/last-build.bin and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/fileHashes/fileHashes.lock b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/fileHashes/fileHashes.lock
-deleted file mode 100644
-index 752a252..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/fileHashes/fileHashes.lock and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/gc.properties b/node_modules/react-native-plaid-link-sdk/android/.gradle/7.4.2/gc.properties
-deleted file mode 100644
-index e69de29..0000000
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/node_modules/react-native-plaid-link-sdk/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock
-deleted file mode 100644
-index 470ca89..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/buildOutputCleanup/cache.properties b/node_modules/react-native-plaid-link-sdk/android/.gradle/buildOutputCleanup/cache.properties
-deleted file mode 100644
-index 1439672..0000000
---- a/node_modules/react-native-plaid-link-sdk/android/.gradle/buildOutputCleanup/cache.properties
-+++ /dev/null
-@@ -1,2 +0,0 @@
--#Thu Nov 09 09:41:17 PST 2023
--gradle.version=7.4.2
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/checksums.lock b/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/checksums.lock
-deleted file mode 100644
-index 34602e1..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/checksums.lock and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/md5-checksums.bin b/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/md5-checksums.bin
-deleted file mode 100644
-index 2420123..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/md5-checksums.bin and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/sha1-checksums.bin b/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/sha1-checksums.bin
-deleted file mode 100644
-index 1081852..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/android/.gradle/checksums/sha1-checksums.bin and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.gradle/vcs-1/gc.properties b/node_modules/react-native-plaid-link-sdk/android/.gradle/vcs-1/gc.properties
-deleted file mode 100644
-index e69de29..0000000
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.idea/gradle.xml b/node_modules/react-native-plaid-link-sdk/android/.idea/gradle.xml
-deleted file mode 100644
-index 0364d75..0000000
---- a/node_modules/react-native-plaid-link-sdk/android/.idea/gradle.xml
-+++ /dev/null
-@@ -1,14 +0,0 @@
--
--
--
--
--
--
--
-\ No newline at end of file
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.idea/misc.xml b/node_modules/react-native-plaid-link-sdk/android/.idea/misc.xml
-deleted file mode 100644
-index a318cae..0000000
---- a/node_modules/react-native-plaid-link-sdk/android/.idea/misc.xml
-+++ /dev/null
-@@ -1,9 +0,0 @@
--
--
--
--
--
--
--
--
--
-\ No newline at end of file
-diff --git a/node_modules/react-native-plaid-link-sdk/android/.idea/vcs.xml b/node_modules/react-native-plaid-link-sdk/android/.idea/vcs.xml
-deleted file mode 100644
-index 6c0b863..0000000
---- a/node_modules/react-native-plaid-link-sdk/android/.idea/vcs.xml
-+++ /dev/null
-@@ -1,6 +0,0 @@
--
--
--
--
--
--
-\ No newline at end of file
-diff --git a/node_modules/react-native-plaid-link-sdk/android/build.gradle b/node_modules/react-native-plaid-link-sdk/android/build.gradle
-index 2d9e2ce..e88208b 100644
---- a/node_modules/react-native-plaid-link-sdk/android/build.gradle
-+++ b/node_modules/react-native-plaid-link-sdk/android/build.gradle
-@@ -12,7 +12,12 @@ allprojects {
-
-
- buildscript {
-- ext.kotlin_version = '1.8.22'
-+ ext {
-+ kotlin_version = '1.8.22'
-+ }
-+ ext.safeExtGet = {prop, fallback ->
-+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
-+ }
- repositories {
- google()
- mavenCentral()
-@@ -25,10 +30,32 @@ buildscript {
- }
- }
-
-+def isNewArchitectureEnabled() {
-+ // To opt-in for the New Architecture, you can either:
-+ // - Set `newArchEnabled` to true inside the `gradle.properties` file
-+ // - Invoke gradle with `-newArchEnabled=true`
-+ // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
-+ return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
-+}
-+
-+if (isNewArchitectureEnabled()) {
-+ apply plugin: "com.facebook.react"
-+}
-+
- apply plugin: 'com.android.library'
- apply plugin: "kotlin-android"
-
- android {
-+
-+ // Used to override the NDK path/version on internal CI or by allowing
-+ // users to customize the NDK path/version from their root project (e.g. for M1 support)
-+ if (rootProject.hasProperty("ndkPath")) {
-+ ndkPath rootProject.ext.ndkPath
-+ }
-+ if (rootProject.hasProperty("ndkVersion")) {
-+ ndkVersion rootProject.ext.ndkVersion
-+ }
-+
- def agpVersion = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')[0].toInteger()
- if (agpVersion >= 7) {
- namespace 'com.plaid'
-@@ -52,6 +79,14 @@ android {
- }
- }
-
-+ sourceSets.main {
-+ java {
-+ if (!isNewArchitectureEnabled()) {
-+ srcDirs += 'src/paper/java'
-+ }
-+ }
-+ }
-+
- buildTypes {
- release {
- debuggable = false
-diff --git a/node_modules/react-native-plaid-link-sdk/android/local.properties b/node_modules/react-native-plaid-link-sdk/android/local.properties
-deleted file mode 100644
-index 0b4e321..0000000
---- a/node_modules/react-native-plaid-link-sdk/android/local.properties
-+++ /dev/null
-@@ -1,8 +0,0 @@
--## This file must *NOT* be checked into Version Control Systems,
--# as it contains information specific to your local configuration.
--#
--# Location of the SDK. This is only used by Gradle.
--# For customization when using a Version Control System, please read the
--# header note.
--#Fri Aug 11 13:58:32 PDT 2023
--sdk.dir=/Users/dtroupe/Library/Android/sdk
-diff --git a/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PLKEmbeddedViewManager.kt b/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PLKEmbeddedViewManager.kt
-index c73011f..66fd266 100644
---- a/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PLKEmbeddedViewManager.kt
-+++ b/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PLKEmbeddedViewManager.kt
-@@ -19,9 +19,9 @@ class PLKEmbeddedViewManager : SimpleViewManager() {
- }
-
- override fun getExportedCustomBubblingEventTypeConstants(): Map {
-- return mapOf(
-- EVENT_NAME to mapOf(
-- "phasedRegistrationNames" to mapOf(
-+ return mutableMapOf(
-+ EVENT_NAME to mutableMapOf(
-+ "phasedRegistrationNames" to mutableMapOf(
- "bubbled" to EVENT_NAME
- )
- ))
-diff --git a/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidModule.kt b/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidModule.kt
-index 293374a..b79352e 100644
---- a/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidModule.kt
-+++ b/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidModule.kt
-@@ -24,9 +24,9 @@ import org.json.JSONException
- import org.json.JSONObject
- import java.util.ArrayList
-
--@ReactModule(name = PlaidModule.TAG)
-+@ReactModule(name = PlaidModule.NAME)
- class PlaidModule internal constructor(reactContext: ReactApplicationContext) :
-- ReactContextBaseJavaModule(reactContext), ActivityEventListener {
-+ NativePlaidLinkModuleAndroidSpec(reactContext), ActivityEventListener {
-
- val mActivityResultManager by lazy { ActivityResultManager() }
-
-@@ -38,11 +38,11 @@ class PlaidModule internal constructor(reactContext: ReactApplicationContext) :
- companion object {
- private const val LINK_TOKEN_PREFIX = "link"
-
-- const val TAG = "PlaidAndroid"
-+ const val NAME = "PlaidAndroid"
- }
-
- override fun getName(): String {
-- return PlaidModule.TAG
-+ return NAME
- }
-
- override fun initialize() {
-@@ -78,7 +78,7 @@ class PlaidModule internal constructor(reactContext: ReactApplicationContext) :
-
- @ReactMethod
- @Suppress("unused")
-- fun startLinkActivityForResult(
-+ override fun startLinkActivityForResult(
- token: String,
- noLoadingState: Boolean,
- logLevel: String,
-@@ -113,6 +113,10 @@ class PlaidModule internal constructor(reactContext: ReactApplicationContext) :
- }
- }
-
-+ override fun addListener(eventName: String?) = Unit
-+
-+ override fun removeListeners(count: Double) = Unit
-+
- private fun maybeGetStringField(obj: JSONObject, fieldName: String): String? {
- if (obj.has(fieldName) && !TextUtils.isEmpty(obj.getString(fieldName))) {
- return obj.getString(fieldName)
-diff --git a/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidPackage.java b/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidPackage.java
-index c59299e..d6b310e 100644
---- a/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidPackage.java
-+++ b/node_modules/react-native-plaid-link-sdk/android/src/main/java/com/plaid/PlaidPackage.java
-@@ -6,19 +6,54 @@ import java.util.List;
- import java.util.Map;
-
- import com.facebook.react.TurboReactPackage;
-+import com.facebook.react.ViewManagerOnDemandReactPackage;
-+import com.facebook.react.bridge.ModuleSpec;
- import com.facebook.react.bridge.NativeModule;
- import com.facebook.react.bridge.ReactApplicationContext;
-+import com.facebook.react.module.annotations.ReactModule;
-+import com.facebook.react.module.annotations.ReactModuleList;
- import com.facebook.react.module.model.ReactModuleInfo;
- import com.facebook.react.module.model.ReactModuleInfoProvider;
-+import com.facebook.react.turbomodule.core.interfaces.TurboModule;
- import com.facebook.react.uimanager.ViewManager;
-
--@SuppressWarnings("unused")
--public class PlaidPackage extends TurboReactPackage {
-+import javax.annotation.Nonnull;
-+import javax.annotation.Nullable;
-
-+@ReactModuleList(nativeModules = {PlaidModule.class})
-+public class PlaidPackage extends TurboReactPackage implements ViewManagerOnDemandReactPackage {
-+
-+ /**
-+ * {@inheritDoc}
-+ */
-+ @Override
-+ public List getViewManagerNames(ReactApplicationContext reactContext) {
-+ return null;
-+ }
-+
-+ @Override
-+ protected List getViewManagers(ReactApplicationContext reactContext) {
-+ return null;
-+ }
-+
-+ /**
-+ * {@inheritDoc}
-+ */
- @Override
-- public NativeModule getModule(
-- String name, ReactApplicationContext reactContext) {
-- return new PlaidModule(reactContext);
-+ public @Nullable
-+ ViewManager createViewManager(
-+ ReactApplicationContext reactContext, String viewManagerName) {
-+ return null;
-+ }
-+
-+ @Override
-+ public NativeModule getModule(String name, @Nonnull ReactApplicationContext reactContext) {
-+ switch (name) {
-+ case PlaidModule.NAME:
-+ return new PlaidModule(reactContext);
-+ default:
-+ return null;
-+ }
- }
-
- @Override
-@@ -28,19 +63,44 @@ public class PlaidPackage extends TurboReactPackage {
-
- @Override
- public ReactModuleInfoProvider getReactModuleInfoProvider() {
-- return () -> {
-- Map map = new HashMap<>();
-- map.put(
-- "PlaidAndroid",
-- new ReactModuleInfo(
-- "PlaidAndroid",
-- "com.reactlibrary.PlaidModule",
-- false,
-- false,
-- true,
-- false,
-- false));
-- return map;
-- };
-+ try {
-+ Class> reactModuleInfoProviderClass =
-+ Class.forName("com.plaid.PlaidPackage$$ReactModuleInfoProvider");
-+ return (ReactModuleInfoProvider) reactModuleInfoProviderClass.newInstance();
-+ } catch (ClassNotFoundException e) {
-+ // ReactModuleSpecProcessor does not run at build-time. Create this ReactModuleInfoProvider by
-+ // hand.
-+ return new ReactModuleInfoProvider() {
-+ @Override
-+ public Map getReactModuleInfos() {
-+ final Map reactModuleInfoMap = new HashMap<>();
-+
-+ Class extends NativeModule>[] moduleList =
-+ new Class[]{
-+ PlaidModule.class,
-+ };
-+
-+ for (Class extends NativeModule> moduleClass : moduleList) {
-+ ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
-+
-+ reactModuleInfoMap.put(
-+ reactModule.name(),
-+ new ReactModuleInfo(
-+ reactModule.name(),
-+ moduleClass.getName(),
-+ reactModule.canOverrideExistingModule(),
-+ reactModule.needsEagerInit(),
-+ reactModule.hasConstants(),
-+ reactModule.isCxxModule(),
-+ TurboModule.class.isAssignableFrom(moduleClass)));
-+ }
-+
-+ return reactModuleInfoMap;
-+ }
-+ };
-+ } catch (InstantiationException | IllegalAccessException e) {
-+ throw new RuntimeException(
-+ "No ReactModuleInfoProvider for com.plaid.PlaidPackage$$ReactModuleInfoProvider", e);
-+ }
- }
- }
-diff --git a/node_modules/react-native-plaid-link-sdk/android/src/paper/java/com/plaid/NativePlaidLinkModuleAndroidSpec.java b/node_modules/react-native-plaid-link-sdk/android/src/paper/java/com/plaid/NativePlaidLinkModuleAndroidSpec.java
-new file mode 100644
-index 0000000..fee5a11
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/android/src/paper/java/com/plaid/NativePlaidLinkModuleAndroidSpec.java
-@@ -0,0 +1,46 @@
-+
-+/**
-+ * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
-+ *
-+ * Do not edit this file as changes may cause incorrect behavior and will be lost
-+ * once the code is regenerated.
-+ *
-+ * @generated by codegen project: GenerateModuleJavaSpec.js
-+ *
-+ * @nolint
-+ */
-+
-+package com.plaid;
-+
-+import com.facebook.proguard.annotations.DoNotStrip;
-+import com.facebook.react.bridge.Callback;
-+import com.facebook.react.bridge.ReactApplicationContext;
-+import com.facebook.react.bridge.ReactContextBaseJavaModule;
-+import com.facebook.react.bridge.ReactMethod;
-+import com.facebook.react.turbomodule.core.interfaces.TurboModule;
-+import javax.annotation.Nonnull;
-+
-+public abstract class NativePlaidLinkModuleAndroidSpec extends ReactContextBaseJavaModule implements TurboModule {
-+ public static final String NAME = "PlaidAndroid";
-+
-+ public NativePlaidLinkModuleAndroidSpec(ReactApplicationContext reactContext) {
-+ super(reactContext);
-+ }
-+
-+ @Override
-+ public @Nonnull String getName() {
-+ return NAME;
-+ }
-+
-+ @ReactMethod
-+ @DoNotStrip
-+ public abstract void startLinkActivityForResult(String token, boolean noLoadingState, String logLevel, Callback onSuccessCallback, Callback onExitCallback);
-+
-+ @ReactMethod
-+ @DoNotStrip
-+ public abstract void addListener(String eventName);
-+
-+ @ReactMethod
-+ @DoNotStrip
-+ public abstract void removeListeners(double count);
-+}
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/EmbeddedLink/EmbeddedLinkView.js b/node_modules/react-native-plaid-link-sdk/dist/EmbeddedLink/EmbeddedLinkView.js
-index c7b1e96..c429da7 100644
---- a/node_modules/react-native-plaid-link-sdk/dist/EmbeddedLink/EmbeddedLinkView.js
-+++ b/node_modules/react-native-plaid-link-sdk/dist/EmbeddedLink/EmbeddedLinkView.js
-@@ -1,55 +1,69 @@
- import React from 'react';
- import NativeEmbeddedLinkView from './NativeEmbeddedLinkView';
- class EmbeddedEvent {
-- constructor(event) {
-- this.eventName = event.eventName;
-- this.metadata = event.metadata;
-- }
-+ constructor(event) {
-+ this.eventName = event.eventName;
-+ this.metadata = event.metadata;
-+ }
- }
- class EmbeddedExit {
-- constructor(event) {
-- this.error = event.error;
-- this.metadata = event.metadata;
-- }
-+ constructor(event) {
-+ this.error = event.error;
-+ this.metadata = event.metadata;
-+ }
- }
- class EmbeddedSuccess {
-- constructor(event) {
-- this.publicToken = event.publicToken;
-- this.metadata = event.metadata;
-- }
-+ constructor(event) {
-+ this.publicToken = event.publicToken;
-+ this.metadata = event.metadata;
-+ }
- }
--export const EmbeddedLinkView = (props) => {
-- const { token, iOSPresentationStyle, onEvent, onSuccess, onExit, style } = props;
-- const onEmbeddedEvent = (event) => {
-- switch (event.nativeEvent.embeddedEventName) {
-- case 'onSuccess': {
-- if (!onSuccess) {
-- return;
-- }
-- const embeddedSuccess = new EmbeddedSuccess(event.nativeEvent);
-- onSuccess(embeddedSuccess);
-- break;
-- }
-- case 'onExit': {
-- if (!onExit) {
-- return;
-- }
-- const embeddedExit = new EmbeddedExit(event.nativeEvent);
-- onExit(embeddedExit);
-- break;
-- }
-- case 'onEvent': {
-- if (!onEvent) {
-- return;
-- }
-- const embeddedEvent = new EmbeddedEvent(event.nativeEvent);
-- onEvent(embeddedEvent);
-- break;
-- }
-- default: {
-- return;
-- }
-+export const EmbeddedLinkView = props => {
-+ const {
-+ token,
-+ iOSPresentationStyle,
-+ onEvent,
-+ onSuccess,
-+ onExit,
-+ style,
-+ } = props;
-+ const onEmbeddedEvent = event => {
-+ switch (event.nativeEvent.embeddedEventName) {
-+ case 'onSuccess': {
-+ if (!onSuccess) {
-+ return;
- }
-- };
-- return ;
-+ const embeddedSuccess = new EmbeddedSuccess(event.nativeEvent);
-+ onSuccess(embeddedSuccess);
-+ break;
-+ }
-+ case 'onExit': {
-+ if (!onExit) {
-+ return;
-+ }
-+ const embeddedExit = new EmbeddedExit(event.nativeEvent);
-+ onExit(embeddedExit);
-+ break;
-+ }
-+ case 'onEvent': {
-+ if (!onEvent) {
-+ return;
-+ }
-+ const embeddedEvent = new EmbeddedEvent(event.nativeEvent);
-+ onEvent(embeddedEvent);
-+ break;
-+ }
-+ default: {
-+ return;
-+ }
-+ }
-+ };
-+ return (
-+
-+ );
- };
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.d.ts b/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.d.ts
-index a48b319..43205dd 100644
---- a/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.d.ts
-+++ b/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.d.ts
-@@ -4,9 +4,9 @@ import { LinkEventListener, PlaidLinkComponentProps, PlaidLinkProps } from './Ty
- * A hook that registers a listener on the Plaid emitter for the 'onEvent' type.
- * The listener is cleaned up when this view is unmounted
- *
-- * @param LinkEventListener the listener to call
-+ * @param linkEventListener the listener to call
- */
--export declare const usePlaidEmitter: (LinkEventListener: LinkEventListener) => void;
-+export declare const usePlaidEmitter: (linkEventListener: LinkEventListener) => void;
- export declare const openLink: (props: PlaidLinkProps) => Promise;
- export declare const dismissLink: () => void;
- export declare const PlaidLink: (props: PlaidLinkComponentProps) => React.JSX.Element;
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.js b/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.js
-index 21da2bc..6c43633 100644
---- a/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.js
-+++ b/node_modules/react-native-plaid-link-sdk/dist/PlaidLink.js
-@@ -1,83 +1,146 @@
--var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
-- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
-- return new (P || (P = Promise))(function (resolve, reject) {
-- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
-- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
-- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
-- step((generator = generator.apply(thisArg, _arguments || [])).next());
-+var __awaiter =
-+ (this && this.__awaiter) ||
-+ function(thisArg, _arguments, P, generator) {
-+ function adopt(value) {
-+ return value instanceof P
-+ ? value
-+ : new P(function(resolve) {
-+ resolve(value);
-+ });
-+ }
-+ return new (P || (P = Promise))(function(resolve, reject) {
-+ function fulfilled(value) {
-+ try {
-+ step(generator.next(value));
-+ } catch (e) {
-+ reject(e);
-+ }
-+ }
-+ function rejected(value) {
-+ try {
-+ step(generator['throw'](value));
-+ } catch (e) {
-+ reject(e);
-+ }
-+ }
-+ function step(result) {
-+ result.done
-+ ? resolve(result.value)
-+ : adopt(result.value).then(fulfilled, rejected);
-+ }
-+ step((generator = generator.apply(thisArg, _arguments || [])).next());
- });
--};
-+ };
-+var _a;
- import React, { useEffect } from 'react';
--import { NativeEventEmitter, NativeModules, Platform, TouchableOpacity, } from 'react-native';
--import { LinkIOSPresentationStyle, LinkLogLevel, } from './Types';
-+import { NativeEventEmitter, Platform, TouchableOpacity } from 'react-native';
-+import { LinkIOSPresentationStyle, LinkLogLevel } from './Types';
-+import RNLinksdkAndroid from './fabric/NativePlaidLinkModuleAndroid';
-+import RNLinksdkiOS from './fabric/NativePlaidLinkModuleiOS';
-+const RNLinksdk =
-+ (_a = Platform.OS === 'android' ? RNLinksdkAndroid : RNLinksdkiOS) !== null &&
-+ _a !== void 0
-+ ? _a
-+ : undefined;
- /**
- * A hook that registers a listener on the Plaid emitter for the 'onEvent' type.
- * The listener is cleaned up when this view is unmounted
- *
-- * @param LinkEventListener the listener to call
-+ * @param linkEventListener the listener to call
- */
--export const usePlaidEmitter = (LinkEventListener) => {
-- useEffect(() => {
-- const emitter = new NativeEventEmitter(Platform.OS === 'ios'
-- ? NativeModules.RNLinksdk
-- : NativeModules.PlaidAndroid);
-- const listener = emitter.addListener('onEvent', LinkEventListener);
-- // Clean up after this effect:
-- return function cleanup() {
-- listener.remove();
-- };
-- }, []);
-+export const usePlaidEmitter = linkEventListener => {
-+ useEffect(() => {
-+ const emitter = new NativeEventEmitter(RNLinksdk);
-+ const listener = emitter.addListener('onEvent', linkEventListener);
-+ // Clean up after this effect:
-+ return function cleanup() {
-+ listener.remove();
-+ };
-+ }, []);
- };
--export const openLink = (props) => __awaiter(void 0, void 0, void 0, function* () {
-- var _a, _b;
-+export const openLink = props =>
-+ __awaiter(void 0, void 0, void 0, function*() {
-+ var _b, _c;
- let config = props.tokenConfig;
-- let noLoadingState = (_a = config.noLoadingState) !== null && _a !== void 0 ? _a : false;
-+ let noLoadingState =
-+ (_b = config.noLoadingState) !== null && _b !== void 0 ? _b : false;
- if (Platform.OS === 'android') {
-- NativeModules.PlaidAndroid.startLinkActivityForResult(config.token, noLoadingState, (_b = config.logLevel) !== null && _b !== void 0 ? _b : LinkLogLevel.ERROR, (result) => {
-- if (props.onSuccess != null) {
-- props.onSuccess(result);
-- }
-- }, (result) => {
-- if (props.onExit != null) {
-- if (result.error != null && result.error.displayMessage != null) {
-- //TODO(RNSDK-118): Remove errorDisplayMessage field in next major update.
-- result.error.errorDisplayMessage = result.error.displayMessage;
-- }
-- props.onExit(result);
-+ if (RNLinksdkAndroid === null) {
-+ throw new Error(
-+ '[react-native-plaid-link-sdk] RNLinksdkAndroid is not defined',
-+ );
-+ }
-+ RNLinksdkAndroid.startLinkActivityForResult(
-+ config.token,
-+ noLoadingState,
-+ (_c = config.logLevel) !== null && _c !== void 0
-+ ? _c
-+ : LinkLogLevel.ERROR,
-+ // @ts-ignore we use Object type in the spec file as it maps to NSDictionary and ReadableMap
-+ result => {
-+ if (props.onSuccess != null) {
-+ props.onSuccess(result);
-+ }
-+ },
-+ result => {
-+ if (props.onExit != null) {
-+ if (result.error != null && result.error.displayMessage != null) {
-+ //TODO(RNSDK-118): Remove errorDisplayMessage field in next major update.
-+ result.error.errorDisplayMessage = result.error.displayMessage;
- }
-- });
-- }
-- else {
-- NativeModules.RNLinksdk.create(config.token, noLoadingState);
-- let presentFullScreen = props.iOSPresentationStyle == LinkIOSPresentationStyle.FULL_SCREEN;
-- NativeModules.RNLinksdk.open(presentFullScreen, (result) => {
-- if (props.onSuccess != null) {
-- props.onSuccess(result);
-- }
-- }, (error, result) => {
-- if (props.onExit != null) {
-- if (error) {
-- var data = result || {};
-- data.error = error;
-- props.onExit(data);
-- }
-- else {
-- props.onExit(result);
-- }
-+ props.onExit(result);
-+ }
-+ },
-+ );
-+ } else {
-+ if (RNLinksdkiOS === null) {
-+ throw new Error(
-+ '[react-native-plaid-link-sdk] RNLinksdkiOS is not defined',
-+ );
-+ }
-+ RNLinksdkiOS.create(config.token, noLoadingState);
-+ let presentFullScreen =
-+ props.iOSPresentationStyle == LinkIOSPresentationStyle.FULL_SCREEN;
-+ RNLinksdkiOS.open(
-+ presentFullScreen,
-+ // @ts-ignore we use Object type in the spec file as it maps to NSDictionary and ReadableMap
-+ result => {
-+ if (props.onSuccess != null) {
-+ props.onSuccess(result);
-+ }
-+ },
-+ (error, result) => {
-+ if (props.onExit != null) {
-+ if (error) {
-+ var data = result || {};
-+ data.error = error;
-+ props.onExit(data);
-+ } else {
-+ props.onExit(result);
- }
-- });
-+ }
-+ },
-+ );
- }
--});
-+ });
- export const dismissLink = () => {
-- if (Platform.OS === 'ios') {
-- NativeModules.RNLinksdk.dismiss();
-+ if (Platform.OS === 'ios') {
-+ if (RNLinksdkiOS === null) {
-+ throw new Error(
-+ '[react-native-plaid-link-sdk] RNLinksdkiOS is not defined',
-+ );
- }
-+ RNLinksdkiOS.dismiss();
-+ }
- };
--export const PlaidLink = (props) => {
-- function onPress() {
-- var _a;
-- (_a = props.onPress) === null || _a === void 0 ? void 0 : _a.call(props);
-- openLink(props);
-- }
-- return {props.children};
-+export const PlaidLink = props => {
-+ function onPress() {
-+ var _a;
-+ (_a = props.onPress) === null || _a === void 0 ? void 0 : _a.call(props);
-+ openLink(props);
-+ }
-+ return (
-+ // @ts-ignore some types directories misconfiguration
-+ {props.children}
-+ );
- };
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/Types.js b/node_modules/react-native-plaid-link-sdk/dist/Types.js
-index 184adad..11b34e3 100644
---- a/node_modules/react-native-plaid-link-sdk/dist/Types.js
-+++ b/node_modules/react-native-plaid-link-sdk/dist/Types.js
-@@ -1,430 +1,681 @@
- export var LinkLogLevel;
--(function (LinkLogLevel) {
-- LinkLogLevel["DEBUG"] = "debug";
-- LinkLogLevel["INFO"] = "info";
-- LinkLogLevel["WARN"] = "warn";
-- LinkLogLevel["ERROR"] = "error";
-+(function(LinkLogLevel) {
-+ LinkLogLevel['DEBUG'] = 'debug';
-+ LinkLogLevel['INFO'] = 'info';
-+ LinkLogLevel['WARN'] = 'warn';
-+ LinkLogLevel['ERROR'] = 'error';
- })(LinkLogLevel || (LinkLogLevel = {}));
- export var PlaidEnvironment;
--(function (PlaidEnvironment) {
-- PlaidEnvironment["PRODUCTION"] = "production";
-- PlaidEnvironment["DEVELOPMENT"] = "development";
-- PlaidEnvironment["SANDBOX"] = "sandbox";
-+(function(PlaidEnvironment) {
-+ PlaidEnvironment['PRODUCTION'] = 'production';
-+ PlaidEnvironment['DEVELOPMENT'] = 'development';
-+ PlaidEnvironment['SANDBOX'] = 'sandbox';
- })(PlaidEnvironment || (PlaidEnvironment = {}));
- export var PlaidProduct;
--(function (PlaidProduct) {
-- PlaidProduct["ASSETS"] = "assets";
-- PlaidProduct["AUTH"] = "auth";
-- PlaidProduct["DEPOSIT_SWITCH"] = "deposit_switch";
-- PlaidProduct["IDENTITY"] = "identity";
-- PlaidProduct["INCOME"] = "income";
-- PlaidProduct["INVESTMENTS"] = "investments";
-- PlaidProduct["LIABILITIES"] = "liabilities";
-- PlaidProduct["LIABILITIES_REPORT"] = "liabilities_report";
-- PlaidProduct["PAYMENT_INITIATION"] = "payment_initiation";
-- PlaidProduct["TRANSACTIONS"] = "transactions";
-+(function(PlaidProduct) {
-+ PlaidProduct['ASSETS'] = 'assets';
-+ PlaidProduct['AUTH'] = 'auth';
-+ PlaidProduct['DEPOSIT_SWITCH'] = 'deposit_switch';
-+ PlaidProduct['IDENTITY'] = 'identity';
-+ PlaidProduct['INCOME'] = 'income';
-+ PlaidProduct['INVESTMENTS'] = 'investments';
-+ PlaidProduct['LIABILITIES'] = 'liabilities';
-+ PlaidProduct['LIABILITIES_REPORT'] = 'liabilities_report';
-+ PlaidProduct['PAYMENT_INITIATION'] = 'payment_initiation';
-+ PlaidProduct['TRANSACTIONS'] = 'transactions';
- })(PlaidProduct || (PlaidProduct = {}));
- export var LinkAccountType;
--(function (LinkAccountType) {
-- LinkAccountType["CREDIT"] = "credit";
-- LinkAccountType["DEPOSITORY"] = "depository";
-- LinkAccountType["INVESTMENT"] = "investment";
-- LinkAccountType["LOAN"] = "loan";
-- LinkAccountType["OTHER"] = "other";
-+(function(LinkAccountType) {
-+ LinkAccountType['CREDIT'] = 'credit';
-+ LinkAccountType['DEPOSITORY'] = 'depository';
-+ LinkAccountType['INVESTMENT'] = 'investment';
-+ LinkAccountType['LOAN'] = 'loan';
-+ LinkAccountType['OTHER'] = 'other';
- })(LinkAccountType || (LinkAccountType = {}));
- export var LinkAccountSubtypes;
--(function (LinkAccountSubtypes) {
-- LinkAccountSubtypes["ALL"] = "all";
-- LinkAccountSubtypes["CREDIT_CARD"] = "credit card";
-- LinkAccountSubtypes["PAYPAL"] = "paypal";
-- LinkAccountSubtypes["AUTO"] = "auto";
-- LinkAccountSubtypes["BUSINESS"] = "business";
-- LinkAccountSubtypes["COMMERCIAL"] = "commercial";
-- LinkAccountSubtypes["CONSTRUCTION"] = "construction";
-- LinkAccountSubtypes["CONSUMER"] = "consumer";
-- LinkAccountSubtypes["HOME_EQUITY"] = "home equity";
-- LinkAccountSubtypes["LINE_OF_CREDIT"] = "line of credit";
-- LinkAccountSubtypes["LOAN"] = "loan";
-- LinkAccountSubtypes["MORTGAGE"] = "mortgage";
-- LinkAccountSubtypes["OVERDRAFT"] = "overdraft";
-- LinkAccountSubtypes["STUDENT"] = "student";
-- LinkAccountSubtypes["CASH_MANAGEMENT"] = "cash management";
-- LinkAccountSubtypes["CD"] = "cd";
-- LinkAccountSubtypes["CHECKING"] = "checking";
-- LinkAccountSubtypes["EBT"] = "ebt";
-- LinkAccountSubtypes["HSA"] = "hsa";
-- LinkAccountSubtypes["MONEY_MARKET"] = "money market";
-- LinkAccountSubtypes["PREPAID"] = "prepaid";
-- LinkAccountSubtypes["SAVINGS"] = "savings";
-- LinkAccountSubtypes["FOUR_0_1_A"] = "401a";
-- LinkAccountSubtypes["FOUR_0_1_K"] = "401k";
-- LinkAccountSubtypes["FOUR_0_3_B"] = "403B";
-- LinkAccountSubtypes["FOUR_5_7_B"] = "457b";
-- LinkAccountSubtypes["FIVE_2_9"] = "529";
-- LinkAccountSubtypes["BROKERAGE"] = "brokerage";
-- LinkAccountSubtypes["CASH_ISA"] = "cash isa";
-- LinkAccountSubtypes["EDUCATION_SAVINGS_ACCOUNT"] = "education savings account";
-- LinkAccountSubtypes["FIXED_ANNUNITY"] = "fixed annuity";
-- LinkAccountSubtypes["GIC"] = "gic";
-- LinkAccountSubtypes["HEALTH_REIMBURSEMENT_ARRANGEMENT"] = "health reimbursement arrangement";
-- LinkAccountSubtypes["IRA"] = "ira";
-- LinkAccountSubtypes["ISA"] = "isa";
-- LinkAccountSubtypes["KEOGH"] = "keogh";
-- LinkAccountSubtypes["LIF"] = "lif";
-- LinkAccountSubtypes["LIRA"] = "lira";
-- LinkAccountSubtypes["LRIF"] = "lrif";
-- LinkAccountSubtypes["LRSP"] = "lrsp";
-- LinkAccountSubtypes["MUTUAL_FUND"] = "mutual fund";
-- LinkAccountSubtypes["NON_TAXABLE_BROKERAGE_ACCOUNT"] = "non-taxable brokerage account";
-- LinkAccountSubtypes["PENSION"] = "pension";
-- LinkAccountSubtypes["PLAN"] = "plan";
-- LinkAccountSubtypes["PRIF"] = "prif";
-- LinkAccountSubtypes["PROFIT_SHARING_PLAN"] = "profit sharing plan";
-- LinkAccountSubtypes["RDSP"] = "rdsp";
-- LinkAccountSubtypes["RESP"] = "resp";
-- LinkAccountSubtypes["RETIREMENT"] = "retirement";
-- LinkAccountSubtypes["RLIF"] = "rlif";
-- LinkAccountSubtypes["ROTH_401K"] = "roth 401k";
-- LinkAccountSubtypes["ROTH"] = "roth";
-- LinkAccountSubtypes["RRIF"] = "rrif";
-- LinkAccountSubtypes["RRSP"] = "rrsp";
-- LinkAccountSubtypes["SARSEP"] = "sarsep";
-- LinkAccountSubtypes["SEP_IRA"] = "sep ira";
-- LinkAccountSubtypes["SIMPLE_IRA"] = "simple ira";
-- LinkAccountSubtypes["SIPP"] = "sipp";
-- LinkAccountSubtypes["STOCK_PLAN"] = "stock plan";
-- LinkAccountSubtypes["TFSA"] = "tfsa";
-- LinkAccountSubtypes["THRIFT_SAVINGS_PLAN"] = "thrift savings plan";
-- LinkAccountSubtypes["TRUST"] = "trust";
-- LinkAccountSubtypes["UGMA"] = "ugma";
-- LinkAccountSubtypes["UTMA"] = "utma";
-- LinkAccountSubtypes["VARIABLE_ANNUITY"] = "variable annuity";
-+(function(LinkAccountSubtypes) {
-+ LinkAccountSubtypes['ALL'] = 'all';
-+ LinkAccountSubtypes['CREDIT_CARD'] = 'credit card';
-+ LinkAccountSubtypes['PAYPAL'] = 'paypal';
-+ LinkAccountSubtypes['AUTO'] = 'auto';
-+ LinkAccountSubtypes['BUSINESS'] = 'business';
-+ LinkAccountSubtypes['COMMERCIAL'] = 'commercial';
-+ LinkAccountSubtypes['CONSTRUCTION'] = 'construction';
-+ LinkAccountSubtypes['CONSUMER'] = 'consumer';
-+ LinkAccountSubtypes['HOME_EQUITY'] = 'home equity';
-+ LinkAccountSubtypes['LINE_OF_CREDIT'] = 'line of credit';
-+ LinkAccountSubtypes['LOAN'] = 'loan';
-+ LinkAccountSubtypes['MORTGAGE'] = 'mortgage';
-+ LinkAccountSubtypes['OVERDRAFT'] = 'overdraft';
-+ LinkAccountSubtypes['STUDENT'] = 'student';
-+ LinkAccountSubtypes['CASH_MANAGEMENT'] = 'cash management';
-+ LinkAccountSubtypes['CD'] = 'cd';
-+ LinkAccountSubtypes['CHECKING'] = 'checking';
-+ LinkAccountSubtypes['EBT'] = 'ebt';
-+ LinkAccountSubtypes['HSA'] = 'hsa';
-+ LinkAccountSubtypes['MONEY_MARKET'] = 'money market';
-+ LinkAccountSubtypes['PREPAID'] = 'prepaid';
-+ LinkAccountSubtypes['SAVINGS'] = 'savings';
-+ LinkAccountSubtypes['FOUR_0_1_A'] = '401a';
-+ LinkAccountSubtypes['FOUR_0_1_K'] = '401k';
-+ LinkAccountSubtypes['FOUR_0_3_B'] = '403B';
-+ LinkAccountSubtypes['FOUR_5_7_B'] = '457b';
-+ LinkAccountSubtypes['FIVE_2_9'] = '529';
-+ LinkAccountSubtypes['BROKERAGE'] = 'brokerage';
-+ LinkAccountSubtypes['CASH_ISA'] = 'cash isa';
-+ LinkAccountSubtypes['EDUCATION_SAVINGS_ACCOUNT'] =
-+ 'education savings account';
-+ LinkAccountSubtypes['FIXED_ANNUNITY'] = 'fixed annuity';
-+ LinkAccountSubtypes['GIC'] = 'gic';
-+ LinkAccountSubtypes['HEALTH_REIMBURSEMENT_ARRANGEMENT'] =
-+ 'health reimbursement arrangement';
-+ LinkAccountSubtypes['IRA'] = 'ira';
-+ LinkAccountSubtypes['ISA'] = 'isa';
-+ LinkAccountSubtypes['KEOGH'] = 'keogh';
-+ LinkAccountSubtypes['LIF'] = 'lif';
-+ LinkAccountSubtypes['LIRA'] = 'lira';
-+ LinkAccountSubtypes['LRIF'] = 'lrif';
-+ LinkAccountSubtypes['LRSP'] = 'lrsp';
-+ LinkAccountSubtypes['MUTUAL_FUND'] = 'mutual fund';
-+ LinkAccountSubtypes['NON_TAXABLE_BROKERAGE_ACCOUNT'] =
-+ 'non-taxable brokerage account';
-+ LinkAccountSubtypes['PENSION'] = 'pension';
-+ LinkAccountSubtypes['PLAN'] = 'plan';
-+ LinkAccountSubtypes['PRIF'] = 'prif';
-+ LinkAccountSubtypes['PROFIT_SHARING_PLAN'] = 'profit sharing plan';
-+ LinkAccountSubtypes['RDSP'] = 'rdsp';
-+ LinkAccountSubtypes['RESP'] = 'resp';
-+ LinkAccountSubtypes['RETIREMENT'] = 'retirement';
-+ LinkAccountSubtypes['RLIF'] = 'rlif';
-+ LinkAccountSubtypes['ROTH_401K'] = 'roth 401k';
-+ LinkAccountSubtypes['ROTH'] = 'roth';
-+ LinkAccountSubtypes['RRIF'] = 'rrif';
-+ LinkAccountSubtypes['RRSP'] = 'rrsp';
-+ LinkAccountSubtypes['SARSEP'] = 'sarsep';
-+ LinkAccountSubtypes['SEP_IRA'] = 'sep ira';
-+ LinkAccountSubtypes['SIMPLE_IRA'] = 'simple ira';
-+ LinkAccountSubtypes['SIPP'] = 'sipp';
-+ LinkAccountSubtypes['STOCK_PLAN'] = 'stock plan';
-+ LinkAccountSubtypes['TFSA'] = 'tfsa';
-+ LinkAccountSubtypes['THRIFT_SAVINGS_PLAN'] = 'thrift savings plan';
-+ LinkAccountSubtypes['TRUST'] = 'trust';
-+ LinkAccountSubtypes['UGMA'] = 'ugma';
-+ LinkAccountSubtypes['UTMA'] = 'utma';
-+ LinkAccountSubtypes['VARIABLE_ANNUITY'] = 'variable annuity';
- })(LinkAccountSubtypes || (LinkAccountSubtypes = {}));
- export class LinkAccountSubtypeCredit {
-- constructor(type, subtype) {
-- this.type = type;
-- this.subtype = subtype;
-- }
-+ constructor(type, subtype) {
-+ this.type = type;
-+ this.subtype = subtype;
-+ }
- }
--LinkAccountSubtypeCredit.ALL = new LinkAccountSubtypeCredit(LinkAccountType.CREDIT, LinkAccountSubtypes.ALL);
--LinkAccountSubtypeCredit.CREDIT_CARD = new LinkAccountSubtypeCredit(LinkAccountType.CREDIT, LinkAccountSubtypes.CREDIT_CARD);
--LinkAccountSubtypeCredit.PAYPAL = new LinkAccountSubtypeCredit(LinkAccountType.CREDIT, LinkAccountSubtypes.PAYPAL);
-+LinkAccountSubtypeCredit.ALL = new LinkAccountSubtypeCredit(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.ALL,
-+);
-+LinkAccountSubtypeCredit.CREDIT_CARD = new LinkAccountSubtypeCredit(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.CREDIT_CARD,
-+);
-+LinkAccountSubtypeCredit.PAYPAL = new LinkAccountSubtypeCredit(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.PAYPAL,
-+);
- export class LinkAccountSubtypeDepository {
-- constructor(type, subtype) {
-- this.type = type;
-- this.subtype = subtype;
-- }
-+ constructor(type, subtype) {
-+ this.type = type;
-+ this.subtype = subtype;
-+ }
- }
--LinkAccountSubtypeDepository.ALL = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.ALL);
--LinkAccountSubtypeDepository.CASH_MANAGEMENT = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.CASH_MANAGEMENT);
--LinkAccountSubtypeDepository.CD = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.CD);
--LinkAccountSubtypeDepository.CHECKING = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.CHECKING);
--LinkAccountSubtypeDepository.EBT = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.EBT);
--LinkAccountSubtypeDepository.HSA = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.HSA);
--LinkAccountSubtypeDepository.MONEY_MARKET = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.MONEY_MARKET);
--LinkAccountSubtypeDepository.PAYPAL = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.PAYPAL);
--LinkAccountSubtypeDepository.PREPAID = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.PREPAID);
--LinkAccountSubtypeDepository.SAVINGS = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.SAVINGS);
-+LinkAccountSubtypeDepository.ALL = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.ALL,
-+);
-+LinkAccountSubtypeDepository.CASH_MANAGEMENT = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.CASH_MANAGEMENT,
-+);
-+LinkAccountSubtypeDepository.CD = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.CD,
-+);
-+LinkAccountSubtypeDepository.CHECKING = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.CHECKING,
-+);
-+LinkAccountSubtypeDepository.EBT = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.EBT,
-+);
-+LinkAccountSubtypeDepository.HSA = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.HSA,
-+);
-+LinkAccountSubtypeDepository.MONEY_MARKET = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.MONEY_MARKET,
-+);
-+LinkAccountSubtypeDepository.PAYPAL = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.PAYPAL,
-+);
-+LinkAccountSubtypeDepository.PREPAID = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.PREPAID,
-+);
-+LinkAccountSubtypeDepository.SAVINGS = new LinkAccountSubtypeDepository(
-+ LinkAccountType.DEPOSITORY,
-+ LinkAccountSubtypes.SAVINGS,
-+);
- export class LinkAccountSubtypeInvestment {
-- constructor(type, subtype) {
-- this.type = type;
-- this.subtype = subtype;
-- }
-+ constructor(type, subtype) {
-+ this.type = type;
-+ this.subtype = subtype;
-+ }
- }
--LinkAccountSubtypeInvestment.ALL = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ALL);
--LinkAccountSubtypeInvestment.BROKERAGE = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.BROKERAGE);
--LinkAccountSubtypeInvestment.CASH_ISA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.CASH_ISA);
--LinkAccountSubtypeInvestment.EDUCATION_SAVINGS_ACCOUNT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.EDUCATION_SAVINGS_ACCOUNT);
--LinkAccountSubtypeInvestment.FIXED_ANNUNITY = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FIXED_ANNUNITY);
--LinkAccountSubtypeInvestment.GIC = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.GIC);
--LinkAccountSubtypeInvestment.HEALTH_REIMBURSEMENT_ARRANGEMENT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.HEALTH_REIMBURSEMENT_ARRANGEMENT);
--LinkAccountSubtypeInvestment.HSA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.HSA);
--LinkAccountSubtypeInvestment.INVESTMENT_401A = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_0_1_A);
--LinkAccountSubtypeInvestment.INVESTMENT_401K = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_0_1_K);
--LinkAccountSubtypeInvestment.INVESTMENT_403B = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_0_3_B);
--LinkAccountSubtypeInvestment.INVESTMENT_457B = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_5_7_B);
--LinkAccountSubtypeInvestment.INVESTMENT_529 = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FIVE_2_9);
--LinkAccountSubtypeInvestment.IRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.IRA);
--LinkAccountSubtypeInvestment.ISA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ISA);
--LinkAccountSubtypeInvestment.KEOGH = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.KEOGH);
--LinkAccountSubtypeInvestment.LIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LIF);
--LinkAccountSubtypeInvestment.LIRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LIRA);
--LinkAccountSubtypeInvestment.LRIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LRIF);
--LinkAccountSubtypeInvestment.LRSP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LRSP);
--LinkAccountSubtypeInvestment.MUTUAL_FUND = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.MUTUAL_FUND);
--LinkAccountSubtypeInvestment.NON_TAXABLE_BROKERAGE_ACCOUNT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.NON_TAXABLE_BROKERAGE_ACCOUNT);
--LinkAccountSubtypeInvestment.PENSION = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PENSION);
--LinkAccountSubtypeInvestment.PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PLAN);
--LinkAccountSubtypeInvestment.PRIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PRIF);
--LinkAccountSubtypeInvestment.PROFIT_SHARING_PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PROFIT_SHARING_PLAN);
--LinkAccountSubtypeInvestment.RDSP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RDSP);
--LinkAccountSubtypeInvestment.RESP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RESP);
--LinkAccountSubtypeInvestment.RETIREMENT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RETIREMENT);
--LinkAccountSubtypeInvestment.RLIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RLIF);
--LinkAccountSubtypeInvestment.ROTH = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ROTH);
--LinkAccountSubtypeInvestment.ROTH_401K = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ROTH_401K);
--LinkAccountSubtypeInvestment.RRIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RRIF);
--LinkAccountSubtypeInvestment.RRSP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RRSP);
--LinkAccountSubtypeInvestment.SARSEP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SARSEP);
--LinkAccountSubtypeInvestment.SEP_IRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SEP_IRA);
--LinkAccountSubtypeInvestment.SIMPLE_IRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SIMPLE_IRA);
--LinkAccountSubtypeInvestment.SIIP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SIPP);
--LinkAccountSubtypeInvestment.STOCK_PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.STOCK_PLAN);
--LinkAccountSubtypeInvestment.TFSA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.TFSA);
--LinkAccountSubtypeInvestment.THRIFT_SAVINGS_PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.THRIFT_SAVINGS_PLAN);
--LinkAccountSubtypeInvestment.TRUST = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.TRUST);
--LinkAccountSubtypeInvestment.UGMA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.UGMA);
--LinkAccountSubtypeInvestment.UTMA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.UTMA);
--LinkAccountSubtypeInvestment.VARIABLE_ANNUITY = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.VARIABLE_ANNUITY);
-+LinkAccountSubtypeInvestment.ALL = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.ALL,
-+);
-+LinkAccountSubtypeInvestment.BROKERAGE = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.BROKERAGE,
-+);
-+LinkAccountSubtypeInvestment.CASH_ISA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.CASH_ISA,
-+);
-+LinkAccountSubtypeInvestment.EDUCATION_SAVINGS_ACCOUNT = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.EDUCATION_SAVINGS_ACCOUNT,
-+);
-+LinkAccountSubtypeInvestment.FIXED_ANNUNITY = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.FIXED_ANNUNITY,
-+);
-+LinkAccountSubtypeInvestment.GIC = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.GIC,
-+);
-+LinkAccountSubtypeInvestment.HEALTH_REIMBURSEMENT_ARRANGEMENT = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.HEALTH_REIMBURSEMENT_ARRANGEMENT,
-+);
-+LinkAccountSubtypeInvestment.HSA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.HSA,
-+);
-+LinkAccountSubtypeInvestment.INVESTMENT_401A = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.FOUR_0_1_A,
-+);
-+LinkAccountSubtypeInvestment.INVESTMENT_401K = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.FOUR_0_1_K,
-+);
-+LinkAccountSubtypeInvestment.INVESTMENT_403B = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.FOUR_0_3_B,
-+);
-+LinkAccountSubtypeInvestment.INVESTMENT_457B = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.FOUR_5_7_B,
-+);
-+LinkAccountSubtypeInvestment.INVESTMENT_529 = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.FIVE_2_9,
-+);
-+LinkAccountSubtypeInvestment.IRA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.IRA,
-+);
-+LinkAccountSubtypeInvestment.ISA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.ISA,
-+);
-+LinkAccountSubtypeInvestment.KEOGH = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.KEOGH,
-+);
-+LinkAccountSubtypeInvestment.LIF = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.LIF,
-+);
-+LinkAccountSubtypeInvestment.LIRA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.LIRA,
-+);
-+LinkAccountSubtypeInvestment.LRIF = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.LRIF,
-+);
-+LinkAccountSubtypeInvestment.LRSP = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.LRSP,
-+);
-+LinkAccountSubtypeInvestment.MUTUAL_FUND = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.MUTUAL_FUND,
-+);
-+LinkAccountSubtypeInvestment.NON_TAXABLE_BROKERAGE_ACCOUNT = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.NON_TAXABLE_BROKERAGE_ACCOUNT,
-+);
-+LinkAccountSubtypeInvestment.PENSION = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.PENSION,
-+);
-+LinkAccountSubtypeInvestment.PLAN = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.PLAN,
-+);
-+LinkAccountSubtypeInvestment.PRIF = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.PRIF,
-+);
-+LinkAccountSubtypeInvestment.PROFIT_SHARING_PLAN = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.PROFIT_SHARING_PLAN,
-+);
-+LinkAccountSubtypeInvestment.RDSP = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.RDSP,
-+);
-+LinkAccountSubtypeInvestment.RESP = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.RESP,
-+);
-+LinkAccountSubtypeInvestment.RETIREMENT = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.RETIREMENT,
-+);
-+LinkAccountSubtypeInvestment.RLIF = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.RLIF,
-+);
-+LinkAccountSubtypeInvestment.ROTH = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.ROTH,
-+);
-+LinkAccountSubtypeInvestment.ROTH_401K = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.ROTH_401K,
-+);
-+LinkAccountSubtypeInvestment.RRIF = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.RRIF,
-+);
-+LinkAccountSubtypeInvestment.RRSP = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.RRSP,
-+);
-+LinkAccountSubtypeInvestment.SARSEP = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.SARSEP,
-+);
-+LinkAccountSubtypeInvestment.SEP_IRA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.SEP_IRA,
-+);
-+LinkAccountSubtypeInvestment.SIMPLE_IRA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.SIMPLE_IRA,
-+);
-+LinkAccountSubtypeInvestment.SIIP = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.SIPP,
-+);
-+LinkAccountSubtypeInvestment.STOCK_PLAN = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.STOCK_PLAN,
-+);
-+LinkAccountSubtypeInvestment.TFSA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.TFSA,
-+);
-+LinkAccountSubtypeInvestment.THRIFT_SAVINGS_PLAN = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.THRIFT_SAVINGS_PLAN,
-+);
-+LinkAccountSubtypeInvestment.TRUST = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.TRUST,
-+);
-+LinkAccountSubtypeInvestment.UGMA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.UGMA,
-+);
-+LinkAccountSubtypeInvestment.UTMA = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.UTMA,
-+);
-+LinkAccountSubtypeInvestment.VARIABLE_ANNUITY = new LinkAccountSubtypeInvestment(
-+ LinkAccountType.INVESTMENT,
-+ LinkAccountSubtypes.VARIABLE_ANNUITY,
-+);
- export class LinkAccountSubtypeLoan {
-- constructor(type, subtype) {
-- this.type = type;
-- this.subtype = subtype;
-- }
-+ constructor(type, subtype) {
-+ this.type = type;
-+ this.subtype = subtype;
-+ }
- }
--LinkAccountSubtypeLoan.ALL = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.ALL);
--LinkAccountSubtypeLoan.AUTO = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.AUTO);
--LinkAccountSubtypeLoan.BUSINESS = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.BUSINESS);
--LinkAccountSubtypeLoan.COMMERCIAL = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.COMMERCIAL);
--LinkAccountSubtypeLoan.CONSTRUCTION = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.CONSTRUCTION);
--LinkAccountSubtypeLoan.CONSUMER = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.CONSUMER);
--LinkAccountSubtypeLoan.HOME_EQUITY = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.HOME_EQUITY);
--LinkAccountSubtypeLoan.LINE_OF_CREDIT = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.LINE_OF_CREDIT);
--LinkAccountSubtypeLoan.LOAN = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.LOAN);
--LinkAccountSubtypeLoan.MORTGAGE = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.MORTGAGE);
--LinkAccountSubtypeLoan.OVERDRAFT = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.OVERDRAFT);
--LinkAccountSubtypeLoan.STUDENT = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.STUDENT);
-+LinkAccountSubtypeLoan.ALL = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.ALL,
-+);
-+LinkAccountSubtypeLoan.AUTO = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.AUTO,
-+);
-+LinkAccountSubtypeLoan.BUSINESS = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.BUSINESS,
-+);
-+LinkAccountSubtypeLoan.COMMERCIAL = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.COMMERCIAL,
-+);
-+LinkAccountSubtypeLoan.CONSTRUCTION = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.CONSTRUCTION,
-+);
-+LinkAccountSubtypeLoan.CONSUMER = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.CONSUMER,
-+);
-+LinkAccountSubtypeLoan.HOME_EQUITY = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.HOME_EQUITY,
-+);
-+LinkAccountSubtypeLoan.LINE_OF_CREDIT = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.LINE_OF_CREDIT,
-+);
-+LinkAccountSubtypeLoan.LOAN = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.LOAN,
-+);
-+LinkAccountSubtypeLoan.MORTGAGE = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.MORTGAGE,
-+);
-+LinkAccountSubtypeLoan.OVERDRAFT = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.OVERDRAFT,
-+);
-+LinkAccountSubtypeLoan.STUDENT = new LinkAccountSubtypeLoan(
-+ LinkAccountType.CREDIT,
-+ LinkAccountSubtypes.STUDENT,
-+);
- export class LinkAccountSubtypeUnknown {
-- constructor(type, subtype) {
-- this.type = type;
-- this.subtype = subtype;
-- }
-+ constructor(type, subtype) {
-+ this.type = type;
-+ this.subtype = subtype;
-+ }
- }
- export var LinkAccountVerificationStatus;
--(function (LinkAccountVerificationStatus) {
-- LinkAccountVerificationStatus["PENDING_AUTOMATIC_VERIFICATION"] = "pending_automatic_verification";
-- LinkAccountVerificationStatus["PENDING_MANUAL_VERIFICATION"] = "pending_manual_verification";
-- LinkAccountVerificationStatus["MANUALLY_VERIFIED"] = "manually_verified";
-+(function(LinkAccountVerificationStatus) {
-+ LinkAccountVerificationStatus['PENDING_AUTOMATIC_VERIFICATION'] =
-+ 'pending_automatic_verification';
-+ LinkAccountVerificationStatus['PENDING_MANUAL_VERIFICATION'] =
-+ 'pending_manual_verification';
-+ LinkAccountVerificationStatus['MANUALLY_VERIFIED'] = 'manually_verified';
- })(LinkAccountVerificationStatus || (LinkAccountVerificationStatus = {}));
- export var LinkExitMetadataStatus;
--(function (LinkExitMetadataStatus) {
-- LinkExitMetadataStatus["CONNECTED"] = "connected";
-- LinkExitMetadataStatus["CHOOSE_DEVICE"] = "choose_device";
-- LinkExitMetadataStatus["REQUIRES_ACCOUNT_SELECTION"] = "requires_account_selection";
-- LinkExitMetadataStatus["REQUIRES_CODE"] = "requires_code";
-- LinkExitMetadataStatus["REQUIRES_CREDENTIALS"] = "requires_credentials";
-- LinkExitMetadataStatus["REQUIRES_EXTERNAL_ACTION"] = "requires_external_action";
-- LinkExitMetadataStatus["REQUIRES_OAUTH"] = "requires_oauth";
-- LinkExitMetadataStatus["REQUIRES_QUESTIONS"] = "requires_questions";
-- LinkExitMetadataStatus["REQUIRES_RECAPTCHA"] = "requires_recaptcha";
-- LinkExitMetadataStatus["REQUIRES_SELECTIONS"] = "requires_selections";
-- LinkExitMetadataStatus["REQUIRES_DEPOSIT_SWITCH_ALLOCATION_CONFIGURATION"] = "requires_deposit_switch_allocation_configuration";
-- LinkExitMetadataStatus["REQUIRES_DEPOSIT_SWITCH_ALLOCATION_SELECTION"] = "requires_deposit_switch_allocation_selection";
-+(function(LinkExitMetadataStatus) {
-+ LinkExitMetadataStatus['CONNECTED'] = 'connected';
-+ LinkExitMetadataStatus['CHOOSE_DEVICE'] = 'choose_device';
-+ LinkExitMetadataStatus['REQUIRES_ACCOUNT_SELECTION'] =
-+ 'requires_account_selection';
-+ LinkExitMetadataStatus['REQUIRES_CODE'] = 'requires_code';
-+ LinkExitMetadataStatus['REQUIRES_CREDENTIALS'] = 'requires_credentials';
-+ LinkExitMetadataStatus['REQUIRES_EXTERNAL_ACTION'] =
-+ 'requires_external_action';
-+ LinkExitMetadataStatus['REQUIRES_OAUTH'] = 'requires_oauth';
-+ LinkExitMetadataStatus['REQUIRES_QUESTIONS'] = 'requires_questions';
-+ LinkExitMetadataStatus['REQUIRES_RECAPTCHA'] = 'requires_recaptcha';
-+ LinkExitMetadataStatus['REQUIRES_SELECTIONS'] = 'requires_selections';
-+ LinkExitMetadataStatus['REQUIRES_DEPOSIT_SWITCH_ALLOCATION_CONFIGURATION'] =
-+ 'requires_deposit_switch_allocation_configuration';
-+ LinkExitMetadataStatus['REQUIRES_DEPOSIT_SWITCH_ALLOCATION_SELECTION'] =
-+ 'requires_deposit_switch_allocation_selection';
- })(LinkExitMetadataStatus || (LinkExitMetadataStatus = {}));
- export var LinkErrorCode;
--(function (LinkErrorCode) {
-- // ITEM_ERROR
-- LinkErrorCode["INVALID_CREDENTIALS"] = "INVALID_CREDENTIALS";
-- LinkErrorCode["INVALID_MFA"] = "INVALID_MFA";
-- LinkErrorCode["ITEM_LOGIN_REQUIRED"] = "ITEM_LOGIN_REQUIRED";
-- LinkErrorCode["INSUFFICIENT_CREDENTIALS"] = "INSUFFICIENT_CREDENTIALS";
-- LinkErrorCode["ITEM_LOCKED"] = "ITEM_LOCKED";
-- LinkErrorCode["USER_SETUP_REQUIRED"] = "USER_SETUP_REQUIRED";
-- LinkErrorCode["MFA_NOT_SUPPORTED"] = "MFA_NOT_SUPPORTED";
-- LinkErrorCode["INVALID_SEND_METHOD"] = "INVALID_SEND_METHOD";
-- LinkErrorCode["NO_ACCOUNTS"] = "NO_ACCOUNTS";
-- LinkErrorCode["ITEM_NOT_SUPPORTED"] = "ITEM_NOT_SUPPORTED";
-- LinkErrorCode["TOO_MANY_VERIFICATION_ATTEMPTS"] = "TOO_MANY_VERIFICATION_ATTEMPTS";
-- LinkErrorCode["INVALD_UPDATED_USERNAME"] = "INVALD_UPDATED_USERNAME";
-- LinkErrorCode["INVALID_UPDATED_USERNAME"] = "INVALID_UPDATED_USERNAME";
-- LinkErrorCode["ITEM_NO_ERROR"] = "ITEM_NO_ERROR";
-- LinkErrorCode["item_no_error"] = "item-no-error";
-- LinkErrorCode["NO_AUTH_ACCOUNTS"] = "NO_AUTH_ACCOUNTS";
-- LinkErrorCode["NO_INVESTMENT_ACCOUNTS"] = "NO_INVESTMENT_ACCOUNTS";
-- LinkErrorCode["NO_INVESTMENT_AUTH_ACCOUNTS"] = "NO_INVESTMENT_AUTH_ACCOUNTS";
-- LinkErrorCode["NO_LIABILITY_ACCOUNTS"] = "NO_LIABILITY_ACCOUNTS";
-- LinkErrorCode["PRODUCTS_NOT_SUPPORTED"] = "PRODUCTS_NOT_SUPPORTED";
-- LinkErrorCode["ITEM_NOT_FOUND"] = "ITEM_NOT_FOUND";
-- LinkErrorCode["ITEM_PRODUCT_NOT_READY"] = "ITEM_PRODUCT_NOT_READY";
-- // INSTITUTION_ERROR
-- LinkErrorCode["INSTITUTION_DOWN"] = "INSTITUTION_DOWN";
-- LinkErrorCode["INSTITUTION_NOT_RESPONDING"] = "INSTITUTION_NOT_RESPONDING";
-- LinkErrorCode["INSTITUTION_NOT_AVAILABLE"] = "INSTITUTION_NOT_AVAILABLE";
-- LinkErrorCode["INSTITUTION_NO_LONGER_SUPPORTED"] = "INSTITUTION_NO_LONGER_SUPPORTED";
-- // API_ERROR
-- LinkErrorCode["INTERNAL_SERVER_ERROR"] = "INTERNAL_SERVER_ERROR";
-- LinkErrorCode["PLANNED_MAINTENANCE"] = "PLANNED_MAINTENANCE";
-- // ASSET_REPORT_ERROR
-- LinkErrorCode["PRODUCT_NOT_ENABLED"] = "PRODUCT_NOT_ENABLED";
-- LinkErrorCode["DATA_UNAVAILABLE"] = "DATA_UNAVAILABLE";
-- LinkErrorCode["ASSET_PRODUCT_NOT_READY"] = "ASSET_PRODUCT_NOT_READY";
-- LinkErrorCode["ASSET_REPORT_GENERATION_FAILED"] = "ASSET_REPORT_GENERATION_FAILED";
-- LinkErrorCode["INVALID_PARENT"] = "INVALID_PARENT";
-- LinkErrorCode["INSIGHTS_NOT_ENABLED"] = "INSIGHTS_NOT_ENABLED";
-- LinkErrorCode["INSIGHTS_PREVIOUSLY_NOT_ENABLED"] = "INSIGHTS_PREVIOUSLY_NOT_ENABLED";
-- // BANK_TRANSFER_ERROR
-- LinkErrorCode["BANK_TRANSFER_LIMIT_EXCEEDED"] = "BANK_TRANSFER_LIMIT_EXCEEDED";
-- LinkErrorCode["BANK_TRANSFER_MISSING_ORIGINATION_ACCOUNT"] = "BANK_TRANSFER_MISSING_ORIGINATION_ACCOUNT";
-- LinkErrorCode["BANK_TRANSFER_INVALID_ORIGINATION_ACCOUNT"] = "BANK_TRANSFER_INVALID_ORIGINATION_ACCOUNT";
-- LinkErrorCode["BANK_TRANSFER_ACCOUNT_BLOCKED"] = "BANK_TRANSFER_ACCOUNT_BLOCKED";
-- LinkErrorCode["BANK_TRANSFER_INSUFFICIENT_FUNDS"] = "BANK_TRANSFER_INSUFFICIENT_FUNDS";
-- LinkErrorCode["BANK_TRANSFER_NOT_CANCELLABLE"] = "BANK_TRANSFER_NOT_CANCELLABLE";
-- LinkErrorCode["BANK_TRANSFER_UNSUPPORTED_ACCOUNT_TYPE"] = "BANK_TRANSFER_UNSUPPORTED_ACCOUNT_TYPE";
-- LinkErrorCode["BANK_TRANSFER_UNSUPPORTED_ENVIRONMENT"] = "BANK_TRANSFER_UNSUPPORTED_ENVIRONMENT";
-- // SANDBOX_ERROR
-- LinkErrorCode["SANDBOX_PRODUCT_NOT_ENABLED"] = "SANDBOX_PRODUCT_NOT_ENABLED";
-- LinkErrorCode["SANDBOX_WEBHOOK_INVALID"] = "SANDBOX_WEBHOOK_INVALID";
-- LinkErrorCode["SANDBOX_BANK_TRANSFER_EVENT_TRANSITION_INVALID"] = "SANDBOX_BANK_TRANSFER_EVENT_TRANSITION_INVALID";
-- // INVALID_REQUEST
-- LinkErrorCode["MISSING_FIELDS"] = "MISSING_FIELDS";
-- LinkErrorCode["UNKNOWN_FIELDS"] = "UNKNOWN_FIELDS";
-- LinkErrorCode["INVALID_FIELD"] = "INVALID_FIELD";
-- LinkErrorCode["INCOMPATIBLE_API_VERSION"] = "INCOMPATIBLE_API_VERSION";
-- LinkErrorCode["INVALID_BODY"] = "INVALID_BODY";
-- LinkErrorCode["INVALID_HEADERS"] = "INVALID_HEADERS";
-- LinkErrorCode["NOT_FOUND"] = "NOT_FOUND";
-- LinkErrorCode["NO_LONGER_AVAILABLE"] = "NO_LONGER_AVAILABLE";
-- LinkErrorCode["SANDBOX_ONLY"] = "SANDBOX_ONLY";
-- LinkErrorCode["INVALID_ACCOUNT_NUMBER"] = "INVALID_ACCOUNT_NUMBER";
-- // INVALID_INPUT
-- // From above ITEM_LOGIN_REQUIRED = "INVALID_CREDENTIALS",
-- LinkErrorCode["INCORRECT_DEPOSIT_AMOUNTS"] = "INCORRECT_DEPOSIT_AMOUNTS";
-- LinkErrorCode["UNAUTHORIZED_ENVIRONMENT"] = "UNAUTHORIZED_ENVIRONMENT";
-- LinkErrorCode["INVALID_PRODUCT"] = "INVALID_PRODUCT";
-- LinkErrorCode["UNAUTHORIZED_ROUTE_ACCESS"] = "UNAUTHORIZED_ROUTE_ACCESS";
-- LinkErrorCode["DIRECT_INTEGRATION_NOT_ENABLED"] = "DIRECT_INTEGRATION_NOT_ENABLED";
-- LinkErrorCode["INVALID_API_KEYS"] = "INVALID_API_KEYS";
-- LinkErrorCode["INVALID_ACCESS_TOKEN"] = "INVALID_ACCESS_TOKEN";
-- LinkErrorCode["INVALID_PUBLIC_TOKEN"] = "INVALID_PUBLIC_TOKEN";
-- LinkErrorCode["INVALID_LINK_TOKEN"] = "INVALID_LINK_TOKEN";
-- LinkErrorCode["INVALID_PROCESSOR_TOKEN"] = "INVALID_PROCESSOR_TOKEN";
-- LinkErrorCode["INVALID_AUDIT_COPY_TOKEN"] = "INVALID_AUDIT_COPY_TOKEN";
-- LinkErrorCode["INVALID_ACCOUNT_ID"] = "INVALID_ACCOUNT_ID";
-- LinkErrorCode["MICRODEPOSITS_ALREADY_VERIFIED"] = "MICRODEPOSITS_ALREADY_VERIFIED";
-- // INVALID_RESULT
-- LinkErrorCode["PLAID_DIRECT_ITEM_IMPORT_RETURNED_INVALID_MFA"] = "PLAID_DIRECT_ITEM_IMPORT_RETURNED_INVALID_MFA";
-- // RATE_LIMIT_EXCEEDED
-- LinkErrorCode["ACCOUNTS_LIMIT"] = "ACCOUNTS_LIMIT";
-- LinkErrorCode["ADDITION_LIMIT"] = "ADDITION_LIMIT";
-- LinkErrorCode["AUTH_LIMIT"] = "AUTH_LIMIT";
-- LinkErrorCode["BALANCE_LIMIT"] = "BALANCE_LIMIT";
-- LinkErrorCode["IDENTITY_LIMIT"] = "IDENTITY_LIMIT";
-- LinkErrorCode["ITEM_GET_LIMIT"] = "ITEM_GET_LIMIT";
-- LinkErrorCode["RATE_LIMIT"] = "RATE_LIMIT";
-- LinkErrorCode["TRANSACTIONS_LIMIT"] = "TRANSACTIONS_LIMIT";
-- // RECAPTCHA_ERROR
-- LinkErrorCode["RECAPTCHA_REQUIRED"] = "RECAPTCHA_REQUIRED";
-- LinkErrorCode["RECAPTCHA_BAD"] = "RECAPTCHA_BAD";
-- // OAUTH_ERROR
-- LinkErrorCode["INCORRECT_OAUTH_NONCE"] = "INCORRECT_OAUTH_NONCE";
-- LinkErrorCode["OAUTH_STATE_ID_ALREADY_PROCESSED"] = "OAUTH_STATE_ID_ALREADY_PROCESSED";
-+(function(LinkErrorCode) {
-+ // ITEM_ERROR
-+ LinkErrorCode['INVALID_CREDENTIALS'] = 'INVALID_CREDENTIALS';
-+ LinkErrorCode['INVALID_MFA'] = 'INVALID_MFA';
-+ LinkErrorCode['ITEM_LOGIN_REQUIRED'] = 'ITEM_LOGIN_REQUIRED';
-+ LinkErrorCode['INSUFFICIENT_CREDENTIALS'] = 'INSUFFICIENT_CREDENTIALS';
-+ LinkErrorCode['ITEM_LOCKED'] = 'ITEM_LOCKED';
-+ LinkErrorCode['USER_SETUP_REQUIRED'] = 'USER_SETUP_REQUIRED';
-+ LinkErrorCode['MFA_NOT_SUPPORTED'] = 'MFA_NOT_SUPPORTED';
-+ LinkErrorCode['INVALID_SEND_METHOD'] = 'INVALID_SEND_METHOD';
-+ LinkErrorCode['NO_ACCOUNTS'] = 'NO_ACCOUNTS';
-+ LinkErrorCode['ITEM_NOT_SUPPORTED'] = 'ITEM_NOT_SUPPORTED';
-+ LinkErrorCode['TOO_MANY_VERIFICATION_ATTEMPTS'] =
-+ 'TOO_MANY_VERIFICATION_ATTEMPTS';
-+ LinkErrorCode['INVALD_UPDATED_USERNAME'] = 'INVALD_UPDATED_USERNAME';
-+ LinkErrorCode['INVALID_UPDATED_USERNAME'] = 'INVALID_UPDATED_USERNAME';
-+ LinkErrorCode['ITEM_NO_ERROR'] = 'ITEM_NO_ERROR';
-+ LinkErrorCode['item_no_error'] = 'item-no-error';
-+ LinkErrorCode['NO_AUTH_ACCOUNTS'] = 'NO_AUTH_ACCOUNTS';
-+ LinkErrorCode['NO_INVESTMENT_ACCOUNTS'] = 'NO_INVESTMENT_ACCOUNTS';
-+ LinkErrorCode['NO_INVESTMENT_AUTH_ACCOUNTS'] = 'NO_INVESTMENT_AUTH_ACCOUNTS';
-+ LinkErrorCode['NO_LIABILITY_ACCOUNTS'] = 'NO_LIABILITY_ACCOUNTS';
-+ LinkErrorCode['PRODUCTS_NOT_SUPPORTED'] = 'PRODUCTS_NOT_SUPPORTED';
-+ LinkErrorCode['ITEM_NOT_FOUND'] = 'ITEM_NOT_FOUND';
-+ LinkErrorCode['ITEM_PRODUCT_NOT_READY'] = 'ITEM_PRODUCT_NOT_READY';
-+ // INSTITUTION_ERROR
-+ LinkErrorCode['INSTITUTION_DOWN'] = 'INSTITUTION_DOWN';
-+ LinkErrorCode['INSTITUTION_NOT_RESPONDING'] = 'INSTITUTION_NOT_RESPONDING';
-+ LinkErrorCode['INSTITUTION_NOT_AVAILABLE'] = 'INSTITUTION_NOT_AVAILABLE';
-+ LinkErrorCode['INSTITUTION_NO_LONGER_SUPPORTED'] =
-+ 'INSTITUTION_NO_LONGER_SUPPORTED';
-+ // API_ERROR
-+ LinkErrorCode['INTERNAL_SERVER_ERROR'] = 'INTERNAL_SERVER_ERROR';
-+ LinkErrorCode['PLANNED_MAINTENANCE'] = 'PLANNED_MAINTENANCE';
-+ // ASSET_REPORT_ERROR
-+ LinkErrorCode['PRODUCT_NOT_ENABLED'] = 'PRODUCT_NOT_ENABLED';
-+ LinkErrorCode['DATA_UNAVAILABLE'] = 'DATA_UNAVAILABLE';
-+ LinkErrorCode['ASSET_PRODUCT_NOT_READY'] = 'ASSET_PRODUCT_NOT_READY';
-+ LinkErrorCode['ASSET_REPORT_GENERATION_FAILED'] =
-+ 'ASSET_REPORT_GENERATION_FAILED';
-+ LinkErrorCode['INVALID_PARENT'] = 'INVALID_PARENT';
-+ LinkErrorCode['INSIGHTS_NOT_ENABLED'] = 'INSIGHTS_NOT_ENABLED';
-+ LinkErrorCode['INSIGHTS_PREVIOUSLY_NOT_ENABLED'] =
-+ 'INSIGHTS_PREVIOUSLY_NOT_ENABLED';
-+ // BANK_TRANSFER_ERROR
-+ LinkErrorCode['BANK_TRANSFER_LIMIT_EXCEEDED'] =
-+ 'BANK_TRANSFER_LIMIT_EXCEEDED';
-+ LinkErrorCode['BANK_TRANSFER_MISSING_ORIGINATION_ACCOUNT'] =
-+ 'BANK_TRANSFER_MISSING_ORIGINATION_ACCOUNT';
-+ LinkErrorCode['BANK_TRANSFER_INVALID_ORIGINATION_ACCOUNT'] =
-+ 'BANK_TRANSFER_INVALID_ORIGINATION_ACCOUNT';
-+ LinkErrorCode['BANK_TRANSFER_ACCOUNT_BLOCKED'] =
-+ 'BANK_TRANSFER_ACCOUNT_BLOCKED';
-+ LinkErrorCode['BANK_TRANSFER_INSUFFICIENT_FUNDS'] =
-+ 'BANK_TRANSFER_INSUFFICIENT_FUNDS';
-+ LinkErrorCode['BANK_TRANSFER_NOT_CANCELLABLE'] =
-+ 'BANK_TRANSFER_NOT_CANCELLABLE';
-+ LinkErrorCode['BANK_TRANSFER_UNSUPPORTED_ACCOUNT_TYPE'] =
-+ 'BANK_TRANSFER_UNSUPPORTED_ACCOUNT_TYPE';
-+ LinkErrorCode['BANK_TRANSFER_UNSUPPORTED_ENVIRONMENT'] =
-+ 'BANK_TRANSFER_UNSUPPORTED_ENVIRONMENT';
-+ // SANDBOX_ERROR
-+ LinkErrorCode['SANDBOX_PRODUCT_NOT_ENABLED'] = 'SANDBOX_PRODUCT_NOT_ENABLED';
-+ LinkErrorCode['SANDBOX_WEBHOOK_INVALID'] = 'SANDBOX_WEBHOOK_INVALID';
-+ LinkErrorCode['SANDBOX_BANK_TRANSFER_EVENT_TRANSITION_INVALID'] =
-+ 'SANDBOX_BANK_TRANSFER_EVENT_TRANSITION_INVALID';
-+ // INVALID_REQUEST
-+ LinkErrorCode['MISSING_FIELDS'] = 'MISSING_FIELDS';
-+ LinkErrorCode['UNKNOWN_FIELDS'] = 'UNKNOWN_FIELDS';
-+ LinkErrorCode['INVALID_FIELD'] = 'INVALID_FIELD';
-+ LinkErrorCode['INCOMPATIBLE_API_VERSION'] = 'INCOMPATIBLE_API_VERSION';
-+ LinkErrorCode['INVALID_BODY'] = 'INVALID_BODY';
-+ LinkErrorCode['INVALID_HEADERS'] = 'INVALID_HEADERS';
-+ LinkErrorCode['NOT_FOUND'] = 'NOT_FOUND';
-+ LinkErrorCode['NO_LONGER_AVAILABLE'] = 'NO_LONGER_AVAILABLE';
-+ LinkErrorCode['SANDBOX_ONLY'] = 'SANDBOX_ONLY';
-+ LinkErrorCode['INVALID_ACCOUNT_NUMBER'] = 'INVALID_ACCOUNT_NUMBER';
-+ // INVALID_INPUT
-+ // From above ITEM_LOGIN_REQUIRED = "INVALID_CREDENTIALS",
-+ LinkErrorCode['INCORRECT_DEPOSIT_AMOUNTS'] = 'INCORRECT_DEPOSIT_AMOUNTS';
-+ LinkErrorCode['UNAUTHORIZED_ENVIRONMENT'] = 'UNAUTHORIZED_ENVIRONMENT';
-+ LinkErrorCode['INVALID_PRODUCT'] = 'INVALID_PRODUCT';
-+ LinkErrorCode['UNAUTHORIZED_ROUTE_ACCESS'] = 'UNAUTHORIZED_ROUTE_ACCESS';
-+ LinkErrorCode['DIRECT_INTEGRATION_NOT_ENABLED'] =
-+ 'DIRECT_INTEGRATION_NOT_ENABLED';
-+ LinkErrorCode['INVALID_API_KEYS'] = 'INVALID_API_KEYS';
-+ LinkErrorCode['INVALID_ACCESS_TOKEN'] = 'INVALID_ACCESS_TOKEN';
-+ LinkErrorCode['INVALID_PUBLIC_TOKEN'] = 'INVALID_PUBLIC_TOKEN';
-+ LinkErrorCode['INVALID_LINK_TOKEN'] = 'INVALID_LINK_TOKEN';
-+ LinkErrorCode['INVALID_PROCESSOR_TOKEN'] = 'INVALID_PROCESSOR_TOKEN';
-+ LinkErrorCode['INVALID_AUDIT_COPY_TOKEN'] = 'INVALID_AUDIT_COPY_TOKEN';
-+ LinkErrorCode['INVALID_ACCOUNT_ID'] = 'INVALID_ACCOUNT_ID';
-+ LinkErrorCode['MICRODEPOSITS_ALREADY_VERIFIED'] =
-+ 'MICRODEPOSITS_ALREADY_VERIFIED';
-+ // INVALID_RESULT
-+ LinkErrorCode['PLAID_DIRECT_ITEM_IMPORT_RETURNED_INVALID_MFA'] =
-+ 'PLAID_DIRECT_ITEM_IMPORT_RETURNED_INVALID_MFA';
-+ // RATE_LIMIT_EXCEEDED
-+ LinkErrorCode['ACCOUNTS_LIMIT'] = 'ACCOUNTS_LIMIT';
-+ LinkErrorCode['ADDITION_LIMIT'] = 'ADDITION_LIMIT';
-+ LinkErrorCode['AUTH_LIMIT'] = 'AUTH_LIMIT';
-+ LinkErrorCode['BALANCE_LIMIT'] = 'BALANCE_LIMIT';
-+ LinkErrorCode['IDENTITY_LIMIT'] = 'IDENTITY_LIMIT';
-+ LinkErrorCode['ITEM_GET_LIMIT'] = 'ITEM_GET_LIMIT';
-+ LinkErrorCode['RATE_LIMIT'] = 'RATE_LIMIT';
-+ LinkErrorCode['TRANSACTIONS_LIMIT'] = 'TRANSACTIONS_LIMIT';
-+ // RECAPTCHA_ERROR
-+ LinkErrorCode['RECAPTCHA_REQUIRED'] = 'RECAPTCHA_REQUIRED';
-+ LinkErrorCode['RECAPTCHA_BAD'] = 'RECAPTCHA_BAD';
-+ // OAUTH_ERROR
-+ LinkErrorCode['INCORRECT_OAUTH_NONCE'] = 'INCORRECT_OAUTH_NONCE';
-+ LinkErrorCode['OAUTH_STATE_ID_ALREADY_PROCESSED'] =
-+ 'OAUTH_STATE_ID_ALREADY_PROCESSED';
- })(LinkErrorCode || (LinkErrorCode = {}));
- export var LinkErrorType;
--(function (LinkErrorType) {
-- LinkErrorType["BANK_TRANSFER"] = "BANK_TRANSFER_ERROR";
-- LinkErrorType["INVALID_REQUEST"] = "INVALID_REQUEST";
-- LinkErrorType["INVALID_RESULT"] = "INVALID_RESULT";
-- LinkErrorType["INVALID_INPUT"] = "INVALID_INPUT";
-- LinkErrorType["INSTITUTION_ERROR"] = "INSTITUTION_ERROR";
-- LinkErrorType["RATE_LIMIT_EXCEEDED"] = "RATE_LIMIT_EXCEEDED";
-- LinkErrorType["API_ERROR"] = "API_ERROR";
-- LinkErrorType["ITEM_ERROR"] = "ITEM_ERROR";
-- LinkErrorType["AUTH_ERROR"] = "AUTH_ERROR";
-- LinkErrorType["ASSET_REPORT_ERROR"] = "ASSET_REPORT_ERROR";
-- LinkErrorType["SANDBOX_ERROR"] = "SANDBOX_ERROR";
-- LinkErrorType["RECAPTCHA_ERROR"] = "RECAPTCHA_ERROR";
-- LinkErrorType["OAUTH_ERROR"] = "OAUTH_ERROR";
-+(function(LinkErrorType) {
-+ LinkErrorType['BANK_TRANSFER'] = 'BANK_TRANSFER_ERROR';
-+ LinkErrorType['INVALID_REQUEST'] = 'INVALID_REQUEST';
-+ LinkErrorType['INVALID_RESULT'] = 'INVALID_RESULT';
-+ LinkErrorType['INVALID_INPUT'] = 'INVALID_INPUT';
-+ LinkErrorType['INSTITUTION_ERROR'] = 'INSTITUTION_ERROR';
-+ LinkErrorType['RATE_LIMIT_EXCEEDED'] = 'RATE_LIMIT_EXCEEDED';
-+ LinkErrorType['API_ERROR'] = 'API_ERROR';
-+ LinkErrorType['ITEM_ERROR'] = 'ITEM_ERROR';
-+ LinkErrorType['AUTH_ERROR'] = 'AUTH_ERROR';
-+ LinkErrorType['ASSET_REPORT_ERROR'] = 'ASSET_REPORT_ERROR';
-+ LinkErrorType['SANDBOX_ERROR'] = 'SANDBOX_ERROR';
-+ LinkErrorType['RECAPTCHA_ERROR'] = 'RECAPTCHA_ERROR';
-+ LinkErrorType['OAUTH_ERROR'] = 'OAUTH_ERROR';
- })(LinkErrorType || (LinkErrorType = {}));
- export var LinkEventName;
--(function (LinkEventName) {
-- LinkEventName["BANK_INCOME_INSIGHTS_COMPLETED"] = "BANK_INCOME_INSIGHTS_COMPLETED";
-- LinkEventName["CLOSE_OAUTH"] = "CLOSE_OAUTH";
-- LinkEventName["ERROR"] = "ERROR";
-- LinkEventName["EXIT"] = "EXIT";
-- LinkEventName["FAIL_OAUTH"] = "FAIL_OAUTH";
-- LinkEventName["HANDOFF"] = "HANDOFF";
-- LinkEventName["IDENTITY_VERIFICATION_START_STEP"] = "IDENTITY_VERIFICATION_START_STEP";
-- LinkEventName["IDENTITY_VERIFICATION_PASS_STEP"] = "IDENTITY_VERIFICATION_PASS_STEP";
-- LinkEventName["IDENTITY_VERIFICATION_FAIL_STEP"] = "IDENTITY_VERIFICATION_FAIL_STEP";
-- LinkEventName["IDENTITY_VERIFICATION_PENDING_REVIEW_STEP"] = "IDENTITY_VERIFICATION_PENDING_REVIEW_STEP";
-- LinkEventName["IDENTITY_VERIFICATION_PENDING_REVIEW_SESSION"] = "IDENTITY_VERIFICATION_PENDING_REVIEW_SESSION";
-- LinkEventName["IDENTITY_VERIFICATION_CREATE_SESSION"] = "IDENTITY_VERIFICATION_CREATE_SESSION";
-- LinkEventName["IDENTITY_VERIFICATION_RESUME_SESSION"] = "IDENTITY_VERIFICATION_RESUME_SESSION";
-- LinkEventName["IDENTITY_VERIFICATION_PASS_SESSION"] = "IDENTITY_VERIFICATION_PASS_SESSION";
-- LinkEventName["IDENTITY_VERIFICATION_FAIL_SESSION"] = "IDENTITY_VERIFICATION_FAIL_SESSION";
-- LinkEventName["IDENTITY_VERIFICATION_OPEN_UI"] = "IDENTITY_VERIFICATION_OPEN_UI";
-- LinkEventName["IDENTITY_VERIFICATION_RESUME_UI"] = "IDENTITY_VERIFICATION_RESUME_UI";
-- LinkEventName["IDENTITY_VERIFICATION_CLOSE_UI"] = "IDENTITY_VERIFICATION_CLOSE_UI";
-- LinkEventName["MATCHED_CONSENT"] = "MATCHED_CONSENT";
-- LinkEventName["MATCHED_SELECT_INSTITUTION"] = "MATCHED_SELECT_INSTITUTION";
-- LinkEventName["MATCHED_SELECT_VERIFY_METHOD"] = "MATCHED_SELECT_VERIFY_METHOD";
-- LinkEventName["OPEN"] = "OPEN";
-- LinkEventName["OPEN_MY_PLAID"] = "OPEN_MY_PLAID";
-- LinkEventName["OPEN_OAUTH"] = "OPEN_OAUTH";
-- LinkEventName["SEARCH_INSTITUTION"] = "SEARCH_INSTITUTION";
-- LinkEventName["SELECT_DEGRADED_INSTITUTION"] = "SELECT_DEGRADED_INSTITUTION";
-- LinkEventName["SELECT_DOWN_INSTITUTION"] = "SELECT_DOWN_INSTITUTION";
-- LinkEventName["SELECT_FILTERED_INSTITUTION"] = "SELECT_FILTERED_INSTITUTION";
-- LinkEventName["SELECT_INSTITUTION"] = "SELECT_INSTITUTION";
-- LinkEventName["SELECT_BRAND"] = "SELECT_BRAND";
-- LinkEventName["SELECT_AUTH_TYPE"] = "SELECT_AUTH_TYPE";
-- LinkEventName["SUBMIT_ACCOUNT_NUMBER"] = "SUBMIT_ACCOUNT_NUMBER";
-- LinkEventName["SUBMIT_DOCUMENTS"] = "SUBMIT_DOCUMENTS";
-- LinkEventName["SUBMIT_DOCUMENTS_SUCCESS"] = "SUBMIT_DOCUMENTS_SUCCESS";
-- LinkEventName["SUBMIT_DOCUMENTS_ERROR"] = "SUBMIT_DOCUMENTS_ERROR";
-- LinkEventName["SUBMIT_ROUTING_NUMBER"] = "SUBMIT_ROUTING_NUMBER";
-- LinkEventName["VIEW_DATA_TYPES"] = "VIEW_DATA_TYPES";
-- LinkEventName["SUBMIT_PHONE"] = "SUBMIT_PHONE";
-- LinkEventName["SKIP_SUBMIT_PHONE"] = "SKIP_SUBMIT_PHONE";
-- LinkEventName["VERIFY_PHONE"] = "VERIFY_PHONE";
-- LinkEventName["SUBMIT_CREDENTIALS"] = "SUBMIT_CREDENTIALS";
-- LinkEventName["SUBMIT_MFA"] = "SUBMIT_MFA";
-- LinkEventName["TRANSITION_VIEW"] = "TRANSITION_VIEW";
-- LinkEventName["CONNECT_NEW_INSTITUTION"] = "CONNECT_NEW_INSTITUTION";
-+(function(LinkEventName) {
-+ LinkEventName['BANK_INCOME_INSIGHTS_COMPLETED'] =
-+ 'BANK_INCOME_INSIGHTS_COMPLETED';
-+ LinkEventName['CLOSE_OAUTH'] = 'CLOSE_OAUTH';
-+ LinkEventName['ERROR'] = 'ERROR';
-+ LinkEventName['EXIT'] = 'EXIT';
-+ LinkEventName['FAIL_OAUTH'] = 'FAIL_OAUTH';
-+ LinkEventName['HANDOFF'] = 'HANDOFF';
-+ LinkEventName['IDENTITY_VERIFICATION_START_STEP'] =
-+ 'IDENTITY_VERIFICATION_START_STEP';
-+ LinkEventName['IDENTITY_VERIFICATION_PASS_STEP'] =
-+ 'IDENTITY_VERIFICATION_PASS_STEP';
-+ LinkEventName['IDENTITY_VERIFICATION_FAIL_STEP'] =
-+ 'IDENTITY_VERIFICATION_FAIL_STEP';
-+ LinkEventName['IDENTITY_VERIFICATION_PENDING_REVIEW_STEP'] =
-+ 'IDENTITY_VERIFICATION_PENDING_REVIEW_STEP';
-+ LinkEventName['IDENTITY_VERIFICATION_PENDING_REVIEW_SESSION'] =
-+ 'IDENTITY_VERIFICATION_PENDING_REVIEW_SESSION';
-+ LinkEventName['IDENTITY_VERIFICATION_CREATE_SESSION'] =
-+ 'IDENTITY_VERIFICATION_CREATE_SESSION';
-+ LinkEventName['IDENTITY_VERIFICATION_RESUME_SESSION'] =
-+ 'IDENTITY_VERIFICATION_RESUME_SESSION';
-+ LinkEventName['IDENTITY_VERIFICATION_PASS_SESSION'] =
-+ 'IDENTITY_VERIFICATION_PASS_SESSION';
-+ LinkEventName['IDENTITY_VERIFICATION_FAIL_SESSION'] =
-+ 'IDENTITY_VERIFICATION_FAIL_SESSION';
-+ LinkEventName['IDENTITY_VERIFICATION_OPEN_UI'] =
-+ 'IDENTITY_VERIFICATION_OPEN_UI';
-+ LinkEventName['IDENTITY_VERIFICATION_RESUME_UI'] =
-+ 'IDENTITY_VERIFICATION_RESUME_UI';
-+ LinkEventName['IDENTITY_VERIFICATION_CLOSE_UI'] =
-+ 'IDENTITY_VERIFICATION_CLOSE_UI';
-+ LinkEventName['MATCHED_CONSENT'] = 'MATCHED_CONSENT';
-+ LinkEventName['MATCHED_SELECT_INSTITUTION'] = 'MATCHED_SELECT_INSTITUTION';
-+ LinkEventName['MATCHED_SELECT_VERIFY_METHOD'] =
-+ 'MATCHED_SELECT_VERIFY_METHOD';
-+ LinkEventName['OPEN'] = 'OPEN';
-+ LinkEventName['OPEN_MY_PLAID'] = 'OPEN_MY_PLAID';
-+ LinkEventName['OPEN_OAUTH'] = 'OPEN_OAUTH';
-+ LinkEventName['SEARCH_INSTITUTION'] = 'SEARCH_INSTITUTION';
-+ LinkEventName['SELECT_DEGRADED_INSTITUTION'] = 'SELECT_DEGRADED_INSTITUTION';
-+ LinkEventName['SELECT_DOWN_INSTITUTION'] = 'SELECT_DOWN_INSTITUTION';
-+ LinkEventName['SELECT_FILTERED_INSTITUTION'] = 'SELECT_FILTERED_INSTITUTION';
-+ LinkEventName['SELECT_INSTITUTION'] = 'SELECT_INSTITUTION';
-+ LinkEventName['SELECT_BRAND'] = 'SELECT_BRAND';
-+ LinkEventName['SELECT_AUTH_TYPE'] = 'SELECT_AUTH_TYPE';
-+ LinkEventName['SUBMIT_ACCOUNT_NUMBER'] = 'SUBMIT_ACCOUNT_NUMBER';
-+ LinkEventName['SUBMIT_DOCUMENTS'] = 'SUBMIT_DOCUMENTS';
-+ LinkEventName['SUBMIT_DOCUMENTS_SUCCESS'] = 'SUBMIT_DOCUMENTS_SUCCESS';
-+ LinkEventName['SUBMIT_DOCUMENTS_ERROR'] = 'SUBMIT_DOCUMENTS_ERROR';
-+ LinkEventName['SUBMIT_ROUTING_NUMBER'] = 'SUBMIT_ROUTING_NUMBER';
-+ LinkEventName['VIEW_DATA_TYPES'] = 'VIEW_DATA_TYPES';
-+ LinkEventName['SUBMIT_PHONE'] = 'SUBMIT_PHONE';
-+ LinkEventName['SKIP_SUBMIT_PHONE'] = 'SKIP_SUBMIT_PHONE';
-+ LinkEventName['VERIFY_PHONE'] = 'VERIFY_PHONE';
-+ LinkEventName['SUBMIT_CREDENTIALS'] = 'SUBMIT_CREDENTIALS';
-+ LinkEventName['SUBMIT_MFA'] = 'SUBMIT_MFA';
-+ LinkEventName['TRANSITION_VIEW'] = 'TRANSITION_VIEW';
-+ LinkEventName['CONNECT_NEW_INSTITUTION'] = 'CONNECT_NEW_INSTITUTION';
- })(LinkEventName || (LinkEventName = {}));
- export var LinkEventViewName;
--(function (LinkEventViewName) {
-- LinkEventViewName["ACCEPT_TOS"] = "ACCEPT_TOS";
-- LinkEventViewName["CONNECTED"] = "CONNECTED";
-- LinkEventViewName["CONSENT"] = "CONSENT";
-- LinkEventViewName["CREDENTIAL"] = "CREDENTIAL";
-- LinkEventViewName["DATA_TRANSPARENCY"] = "DATA_TRANSPARENCY";
-- LinkEventViewName["DATA_TRANSPARENCY_CONSENT"] = "DATA_TRANSPARENCY_CONSENT";
-- LinkEventViewName["DOCUMENTARY_VERIFICATION"] = "DOCUMENTARY_VERIFICATION";
-- LinkEventViewName["ERROR"] = "ERROR";
-- LinkEventViewName["EXIT"] = "EXIT";
-- LinkEventViewName["KYC_CHECK"] = "KYC_CHECK";
-- LinkEventViewName["SELFIE_CHECK"] = "SELFIE_CHECK";
-- LinkEventViewName["LOADING"] = "LOADING";
-- LinkEventViewName["MATCHED_CONSENT"] = "MATCHED_CONSENT";
-- LinkEventViewName["MATCHED_CREDENTIAL"] = "MATCHED_CREDENTIAL";
-- LinkEventViewName["MATCHED_MFA"] = "MATCHED_MFA";
-- LinkEventViewName["MFA"] = "MFA";
-- LinkEventViewName["NUMBERS"] = "NUMBERS";
-- LinkEventViewName["NUMBERS_SELECT_INSTITUTION"] = "NUMBERS_SELECT_INSTITUTION";
-- LinkEventViewName["OAUTH"] = "OAUTH";
-- LinkEventViewName["RECAPTCHA"] = "RECAPTCHA";
-- LinkEventViewName["RISK_CHECK"] = "RISK_CHECK";
-- LinkEventViewName["SCREENING"] = "SCREENING";
-- LinkEventViewName["SELECT_ACCOUNT"] = "SELECT_ACCOUNT";
-- LinkEventViewName["SELECT_AUTH_TYPE"] = "SELECT_AUTH_TYPE";
-- LinkEventViewName["SUBMIT_PHONE"] = "SUBMIT_PHONE";
-- LinkEventViewName["VERIFY_PHONE"] = "VERIFY_PHONE";
-- LinkEventViewName["SELECT_SAVED_INSTITUTION"] = "SELECT_SAVED_INSTITUTION";
-- LinkEventViewName["SELECT_SAVED_ACCOUNT"] = "SELECT_SAVED_ACCOUNT";
-- LinkEventViewName["SELECT_BRAND"] = "SELECT_BRAND";
-- LinkEventViewName["SELECT_INSTITUTION"] = "SELECT_INSTITUTION";
-- LinkEventViewName["SUBMIT_DOCUMENTS"] = "SUBMIT_DOCUMENTS";
-- LinkEventViewName["SUBMIT_DOCUMENTS_SUCCESS"] = "SUBMIT_DOCUMENTS_SUCCESS";
-- LinkEventViewName["SUBMIT_DOCUMENTS_ERROR"] = "SUBMIT_DOCUMENTS_ERROR";
-- LinkEventViewName["UPLOAD_DOCUMENTS"] = "UPLOAD_DOCUMENTS";
-- LinkEventViewName["VERIFY_SMS"] = "VERIFY_SMS";
-+(function(LinkEventViewName) {
-+ LinkEventViewName['ACCEPT_TOS'] = 'ACCEPT_TOS';
-+ LinkEventViewName['CONNECTED'] = 'CONNECTED';
-+ LinkEventViewName['CONSENT'] = 'CONSENT';
-+ LinkEventViewName['CREDENTIAL'] = 'CREDENTIAL';
-+ LinkEventViewName['DATA_TRANSPARENCY'] = 'DATA_TRANSPARENCY';
-+ LinkEventViewName['DATA_TRANSPARENCY_CONSENT'] = 'DATA_TRANSPARENCY_CONSENT';
-+ LinkEventViewName['DOCUMENTARY_VERIFICATION'] = 'DOCUMENTARY_VERIFICATION';
-+ LinkEventViewName['ERROR'] = 'ERROR';
-+ LinkEventViewName['EXIT'] = 'EXIT';
-+ LinkEventViewName['KYC_CHECK'] = 'KYC_CHECK';
-+ LinkEventViewName['SELFIE_CHECK'] = 'SELFIE_CHECK';
-+ LinkEventViewName['LOADING'] = 'LOADING';
-+ LinkEventViewName['MATCHED_CONSENT'] = 'MATCHED_CONSENT';
-+ LinkEventViewName['MATCHED_CREDENTIAL'] = 'MATCHED_CREDENTIAL';
-+ LinkEventViewName['MATCHED_MFA'] = 'MATCHED_MFA';
-+ LinkEventViewName['MFA'] = 'MFA';
-+ LinkEventViewName['NUMBERS'] = 'NUMBERS';
-+ LinkEventViewName['NUMBERS_SELECT_INSTITUTION'] =
-+ 'NUMBERS_SELECT_INSTITUTION';
-+ LinkEventViewName['OAUTH'] = 'OAUTH';
-+ LinkEventViewName['RECAPTCHA'] = 'RECAPTCHA';
-+ LinkEventViewName['RISK_CHECK'] = 'RISK_CHECK';
-+ LinkEventViewName['SCREENING'] = 'SCREENING';
-+ LinkEventViewName['SELECT_ACCOUNT'] = 'SELECT_ACCOUNT';
-+ LinkEventViewName['SELECT_AUTH_TYPE'] = 'SELECT_AUTH_TYPE';
-+ LinkEventViewName['SUBMIT_PHONE'] = 'SUBMIT_PHONE';
-+ LinkEventViewName['VERIFY_PHONE'] = 'VERIFY_PHONE';
-+ LinkEventViewName['SELECT_SAVED_INSTITUTION'] = 'SELECT_SAVED_INSTITUTION';
-+ LinkEventViewName['SELECT_SAVED_ACCOUNT'] = 'SELECT_SAVED_ACCOUNT';
-+ LinkEventViewName['SELECT_BRAND'] = 'SELECT_BRAND';
-+ LinkEventViewName['SELECT_INSTITUTION'] = 'SELECT_INSTITUTION';
-+ LinkEventViewName['SUBMIT_DOCUMENTS'] = 'SUBMIT_DOCUMENTS';
-+ LinkEventViewName['SUBMIT_DOCUMENTS_SUCCESS'] = 'SUBMIT_DOCUMENTS_SUCCESS';
-+ LinkEventViewName['SUBMIT_DOCUMENTS_ERROR'] = 'SUBMIT_DOCUMENTS_ERROR';
-+ LinkEventViewName['UPLOAD_DOCUMENTS'] = 'UPLOAD_DOCUMENTS';
-+ LinkEventViewName['VERIFY_SMS'] = 'VERIFY_SMS';
- })(LinkEventViewName || (LinkEventViewName = {}));
- /// Methods to present Link on iOS.
- /// FULL_SCREEN is the converts to UIModalPresentationOverFullScreen on the native side.
- /// MODAL will use the default presentation style for iOS which is UIModalPresentationAutomatic.
- export var LinkIOSPresentationStyle;
--(function (LinkIOSPresentationStyle) {
-- LinkIOSPresentationStyle["FULL_SCREEN"] = "FULL_SCREEN";
-- LinkIOSPresentationStyle["MODAL"] = "MODAL";
-+(function(LinkIOSPresentationStyle) {
-+ LinkIOSPresentationStyle['FULL_SCREEN'] = 'FULL_SCREEN';
-+ LinkIOSPresentationStyle['MODAL'] = 'MODAL';
- })(LinkIOSPresentationStyle || (LinkIOSPresentationStyle = {}));
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.d.ts b/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.d.ts
-index cd4ccde..cb0ff5c 100644
---- a/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.d.ts
-+++ b/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.d.ts
-@@ -1 +1 @@
--declare const Types: any;
-+export {};
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.js b/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.js
-index 831866b..f38aff8 100644
---- a/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.js
-+++ b/node_modules/react-native-plaid-link-sdk/dist/__tests__/Types.tests.js
-@@ -1,14 +1,14 @@
--"use strict";
- const Types = require('./../Types');
- test('test token configuration', () => {
-- const linkTokenConfiguration = {
-- token: "test-token",
-- noLoadingState: false,
-- logLevel: Types.LinkLogLevel.DEBUG,
-- extras: null,
-- };
-- expect(linkTokenConfiguration.noLoadingState).toBe(false);
-- expect(linkTokenConfiguration.token).toBe("test-token");
-- expect(linkTokenConfiguration.logLevel).toBe(Types.LinkLogLevel.DEBUG);
-- expect(linkTokenConfiguration.extras).toBe(null);
-+ const linkTokenConfiguration = {
-+ token: 'test-token',
-+ noLoadingState: false,
-+ logLevel: Types.LinkLogLevel.DEBUG,
-+ extras: null,
-+ };
-+ expect(linkTokenConfiguration.noLoadingState).toBe(false);
-+ expect(linkTokenConfiguration.token).toBe('test-token');
-+ expect(linkTokenConfiguration.logLevel).toBe(Types.LinkLogLevel.DEBUG);
-+ expect(linkTokenConfiguration.extras).toBe(null);
- });
-+export {};
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/check_version_hook.d.ts b/node_modules/react-native-plaid-link-sdk/dist/check_version_hook.d.ts
-new file mode 100644
-index 0000000..cb0ff5c
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/check_version_hook.d.ts
-@@ -0,0 +1 @@
-+export {};
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/check_version_hook.js b/node_modules/react-native-plaid-link-sdk/dist/check_version_hook.js
-new file mode 100644
-index 0000000..34a47d4
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/check_version_hook.js
-@@ -0,0 +1,15 @@
-+'use strict';
-+const fs = require('fs');
-+const rn_version = JSON.parse(fs.readFileSync('package.json', 'utf-8'))[
-+ 'version'
-+];
-+const android_version = fs
-+ .readFileSync('android/src/main/AndroidManifest.xml', 'utf-8')
-+ .match(/(?<=value=").*(?=")/)[0];
-+if (rn_version != android_version) {
-+ console.error('Commit failed SDK version mismatch');
-+ console.error(
-+ 'Please ensure package.json and android/src/main/AndroidManifest.xml have the same version',
-+ );
-+ process.exit(-1);
-+}
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModule.d.ts b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModule.d.ts
-new file mode 100644
-index 0000000..1de3019
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModule.d.ts
-@@ -0,0 +1,14 @@
-+import { TurboModule } from 'react-native';
-+import { Int32 } from 'react-native/Libraries/Types/CodegenTypes';
-+import { LinkSuccess as UnsafeObject, LinkExit as Double, LinkError as Float } from '../Types';
-+export interface Spec extends TurboModule {
-+ continueFromRedirectUriString(redirectUriString: string): void;
-+ create(configuration: Object): void;
-+ open(onSuccess: (success: UnsafeObject) => void, onExit: (error: Float, result: Double) => void): void;
-+ dismiss(): void;
-+ startLinkActivityForResult(data: string, onSuccessCallback: (result: UnsafeObject) => void, onExitCallback: (result: Double) => void): void;
-+ addListener(eventName: string): void;
-+ removeListeners(count: Int32): void;
-+}
-+declare const _default: Spec;
-+export default _default;
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModule.js b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModule.js
-new file mode 100644
-index 0000000..310a9c5
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModule.js
-@@ -0,0 +1,4 @@
-+// we use Object type because methods on the native side use NSDictionary and ReadableMap
-+// and we want to stay compatible with those
-+import { TurboModuleRegistry } from 'react-native';
-+export default TurboModuleRegistry.getEnforcing('RNLinksdk');
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleAndroid.d.ts b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleAndroid.d.ts
-new file mode 100644
-index 0000000..82f29a1
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleAndroid.d.ts
-@@ -0,0 +1,9 @@
-+import { TurboModule } from 'react-native';
-+import { Int32, UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
-+export interface Spec extends TurboModule {
-+ startLinkActivityForResult(token: string, noLoadingState: boolean, logLevel: string, onSuccessCallback: (result: UnsafeObject) => void, onExitCallback: (result: UnsafeObject) => void): void;
-+ addListener(eventName: string): void;
-+ removeListeners(count: Int32): void;
-+}
-+declare const _default: Spec | null;
-+export default _default;
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleAndroid.js b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleAndroid.js
-new file mode 100644
-index 0000000..d0ea456
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleAndroid.js
-@@ -0,0 +1,4 @@
-+// we use Object type because methods on the native side use NSDictionary and ReadableMap
-+// and we want to stay compatible with those
-+import { TurboModuleRegistry } from 'react-native';
-+export default TurboModuleRegistry.get('PlaidAndroid');
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleiOS.d.ts b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleiOS.d.ts
-new file mode 100644
-index 0000000..aefee8c
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleiOS.d.ts
-@@ -0,0 +1,11 @@
-+import { TurboModule } from 'react-native';
-+import { Int32, UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
-+export interface Spec extends TurboModule {
-+ create(token: string, noLoadingState: boolean): void;
-+ open(fullScreen: boolean, onSuccess: (success: UnsafeObject) => void, onExit: (error: UnsafeObject, result: UnsafeObject) => void): void;
-+ dismiss(): void;
-+ addListener(eventName: string): void;
-+ removeListeners(count: Int32): void;
-+}
-+declare const _default: Spec | null;
-+export default _default;
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleiOS.js b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleiOS.js
-new file mode 100644
-index 0000000..99845a1
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/dist/fabric/NativePlaidLinkModuleiOS.js
-@@ -0,0 +1,4 @@
-+// we use Object type because methods on the native side use NSDictionary and ReadableMap
-+// and we want to stay compatible with those
-+import { TurboModuleRegistry } from 'react-native';
-+export default TurboModuleRegistry.get('RNLinksdk');
-diff --git a/node_modules/react-native-plaid-link-sdk/dist/index.js b/node_modules/react-native-plaid-link-sdk/dist/index.js
-index 68c2d4b..acad079 100644
---- a/node_modules/react-native-plaid-link-sdk/dist/index.js
-+++ b/node_modules/react-native-plaid-link-sdk/dist/index.js
-@@ -1,6 +1,6 @@
--import { openLink, dismissLink, usePlaidEmitter, PlaidLink, } from './PlaidLink';
-+import { openLink, dismissLink, usePlaidEmitter, PlaidLink } from './PlaidLink';
- export * from './Types';
- export default PlaidLink;
--export { PlaidLink, openLink, dismissLink, usePlaidEmitter, };
-+export { PlaidLink, openLink, dismissLink, usePlaidEmitter };
- // Components
- export { EmbeddedLinkView } from './EmbeddedLink/EmbeddedLinkView';
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.h b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.h
-index 8a1c350..035b91c 100644
---- a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.h
-+++ b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.h
-@@ -1,15 +1,17 @@
--
--#if __has_include()
--#import
--#import
--#else
--#import "RCTBridgeModule.h"
--#import "RCTEventEmitter.h"
-+#ifdef RCT_NEW_ARCH_ENABLED
-+#import
- #endif
-+#import
-+#import "RCTEventEmitter.h"
-
- #import
-
--@interface RNLinksdk : RCTEventEmitter
-+@interface RNLinksdk : RCTEventEmitter
-+#ifdef RCT_NEW_ARCH_ENABLED
-+
-+#else
-+
-+#endif
-
- + (NSDictionary *)dictionaryFromSuccess:(PLKLinkSuccess *)success;
- + (NSDictionary *)dictionaryFromEvent:(PLKLinkEvent *)event;
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.mm b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.mm
-index ef3fe85..b3b92d6 100644
---- a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.mm
-+++ b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.mm
-@@ -1,4 +1,5 @@
- #import "RNLinksdk.h"
-+#import "RNPlaidHelper.h"
-
- #import
- #import
-@@ -66,11 +67,11 @@ - (void)stopObserving {
- self.hasObservers = NO;
- }
-
--RCT_EXPORT_METHOD(create:(NSString*)token :(BOOL)noLoadingState) {
-- __weak typeof(self) weakSelf = self;
-+RCT_EXPORT_METHOD(create:(NSString*)token noLoadingState:(BOOL)noLoadingState) {
-+ __weak RNLinksdk *weakSelf = self;
-
- void (^onSuccess)(PLKLinkSuccess *) = ^(PLKLinkSuccess *success) {
-- __typeof(weakSelf) strongSelf = weakSelf;
-+ RNLinksdk *strongSelf = weakSelf;
-
- if (strongSelf.successCallback) {
- NSDictionary *jsMetadata = [RNLinksdk dictionaryFromSuccess:success];
-@@ -80,7 +81,7 @@ - (void)stopObserving {
- };
-
- void (^onExit)(PLKLinkExit *) = ^(PLKLinkExit *exit) {
-- __typeof(weakSelf) strongSelf = weakSelf;
-+ RNLinksdk *strongSelf = weakSelf;
-
- if (strongSelf.exitCallback) {
- NSDictionary *exitMetadata = [RNLinksdk dictionaryFromExit:exit];
-@@ -94,7 +95,7 @@ - (void)stopObserving {
- };
-
- void (^onEvent)(PLKLinkEvent *) = ^(PLKLinkEvent *event) {
-- __typeof(weakSelf) strongSelf = weakSelf;
-+ RNLinksdk *strongSelf = weakSelf;
- if (strongSelf.hasObservers) {
- NSDictionary *eventDictionary = [RNLinksdk dictionaryFromEvent:event];
- [strongSelf sendEventWithName:kRNLinkKitOnEventEvent
-@@ -108,11 +109,11 @@ - (void)stopObserving {
- config.noLoadingState = noLoadingState;
-
- NSError *creationError = nil;
-- self.linkHandler = [PLKPlaid createWithLinkTokenConfiguration:config error:&creationError];
-+ self.linkHandler = [RNPlaidHelper createWithLinkTokenConfiguration:config error:&creationError];
- self.creationError = creationError;
- }
-
--RCT_EXPORT_METHOD(open: (BOOL)fullScreen :(RCTResponseSenderBlock)onSuccess :(RCTResponseSenderBlock)onExit) {
-+RCT_EXPORT_METHOD(open:(BOOL)fullScreen onSuccess:(RCTResponseSenderBlock)onSuccess onExit:(RCTResponseSenderBlock)onExit) {
- if (self.linkHandler) {
- self.successCallback = onSuccess;
- self.exitCallback = onExit;
-@@ -122,7 +123,7 @@ - (void)stopObserving {
- // unnecessarily invoked.
- __block bool didPresent = NO;
-
-- __weak typeof(self) weakSelf = self;
-+ __weak RNLinksdk *weakSelf = self;
- void(^presentationHandler)(UIViewController *) = ^(UIViewController *linkViewController) {
-
- if (fullScreen) {
-@@ -619,4 +620,12 @@ + (NSDictionary *)dictionaryFromExit:(PLKLinkExit *)exit {
- };
- }
-
-+#if RCT_NEW_ARCH_ENABLED
-+- (std::shared_ptr)getTurboModule:
-+ (const facebook::react::ObjCTurboModule::InitParams &)params
-+{
-+ return std::make_shared(params);
-+}
-+#endif
-+
- @end
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata
-deleted file mode 100644
-index 919434a..0000000
---- a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata
-+++ /dev/null
-@@ -1,7 +0,0 @@
--
--
--
--
--
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
-deleted file mode 100644
-index 18d9810..0000000
---- a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
-+++ /dev/null
-@@ -1,8 +0,0 @@
--
--
--
--
-- IDEDidComputeMac32BitWarning
--
--
--
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/xcuserdata/dtroupe.xcuserdatad/UserInterfaceState.xcuserstate b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/xcuserdata/dtroupe.xcuserdatad/UserInterfaceState.xcuserstate
-deleted file mode 100644
-index 47e9cc2..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/project.xcworkspace/xcuserdata/dtroupe.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/xcuserdata/dtroupe.xcuserdatad/xcschemes/xcschememanagement.plist b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/xcuserdata/dtroupe.xcuserdatad/xcschemes/xcschememanagement.plist
-deleted file mode 100644
-index 5b4fa70..0000000
---- a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcodeproj/xcuserdata/dtroupe.xcuserdatad/xcschemes/xcschememanagement.plist
-+++ /dev/null
-@@ -1,19 +0,0 @@
--
--
--
--
-- SchemeUserState
--
-- RNLinksdk.xcscheme_^#shared#^_
--
-- orderHint
-- 0
--
-- RNLinksdkUnitTests.xcscheme_^#shared#^_
--
-- orderHint
-- 1
--
--
--
--
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcworkspace/xcuserdata/dtroupe.xcuserdatad/UserInterfaceState.xcuserstate b/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcworkspace/xcuserdata/dtroupe.xcuserdatad/UserInterfaceState.xcuserstate
-deleted file mode 100644
-index 824773d..0000000
-Binary files a/node_modules/react-native-plaid-link-sdk/ios/RNLinksdk.xcworkspace/xcuserdata/dtroupe.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNPlaidHelper.h b/node_modules/react-native-plaid-link-sdk/ios/RNPlaidHelper.h
-new file mode 100644
-index 0000000..535d333
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/ios/RNPlaidHelper.h
-@@ -0,0 +1,7 @@
-+#import
-+
-+@interface RNPlaidHelper : NSObject
-+
-++ (id _Nullable)createWithLinkTokenConfiguration:(PLKLinkTokenConfiguration * _Nonnull)linkTokenConfiguration error:(NSError * _Nullable * _Nullable)error;
-+
-+@end
-diff --git a/node_modules/react-native-plaid-link-sdk/ios/RNPlaidHelper.m b/node_modules/react-native-plaid-link-sdk/ios/RNPlaidHelper.m
-new file mode 100644
-index 0000000..2288299
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/ios/RNPlaidHelper.m
-@@ -0,0 +1,10 @@
-+#import "RNPlaidHelper.h"
-+
-+@implementation RNPlaidHelper
-+
-++ (id _Nullable)createWithLinkTokenConfiguration:(PLKLinkTokenConfiguration * _Nonnull)linkTokenConfiguration error:(NSError * _Nullable * _Nullable)error
-+{
-+ return [PLKPlaid createWithLinkTokenConfiguration:linkTokenConfiguration error:error];
-+}
-+
-+@end
-diff --git a/node_modules/react-native-plaid-link-sdk/package.json b/node_modules/react-native-plaid-link-sdk/package.json
-index 22c7d2c..3d1b85c 100644
---- a/node_modules/react-native-plaid-link-sdk/package.json
-+++ b/node_modules/react-native-plaid-link-sdk/package.json
-@@ -4,11 +4,13 @@
- "description": "React Native Plaid Link SDK",
- "main": "dist/index.js",
- "types": "dist/index.d.ts",
-+ "react-native": "src/index.ts",
- "files": [
- "dist/**/*",
- "android/**/*",
-- "ios",
-- "react-native-plaid-link-sdk.podspec"
-+ "ios/**/*",
-+ "react-native-plaid-link-sdk.podspec",
-+ "src/**/*"
- ],
- "scripts": {
- "lint": "eslint \"./**/*.{js,jsx}\" --fix",
-@@ -47,7 +49,7 @@
- "@react-native-community/eslint-plugin": "^1.1.0",
- "@types/jest": "^26.0.14",
- "@types/react": "^16.14.20",
-- "@types/react-native": "^0.66.0",
-+ "@types/react-native": "^0.71.3",
- "@types/react-test-renderer": "^16.9.3",
- "@typescript-eslint/eslint-plugin": "^4.33.0",
- "@typescript-eslint/parser": "^4.33.0",
-@@ -62,5 +64,16 @@
- "react": "18.0.0",
- "react-native": "0.69.9",
- "typescript": "^4.9.5"
-+ },
-+ "dependencies": {
-+ "react-native-plaid-link-sdk": "^10.4.0"
-+ },
-+ "codegenConfig": {
-+ "name": "rnplaidlink",
-+ "type": "modules",
-+ "jsSrcsDir": "./src/fabric",
-+ "android": {
-+ "javaPackageName": "com.plaid"
-+ }
- }
- }
-diff --git a/node_modules/react-native-plaid-link-sdk/react-native-plaid-link-sdk.podspec b/node_modules/react-native-plaid-link-sdk/react-native-plaid-link-sdk.podspec
-index ee59a19..40ac7df 100644
---- a/node_modules/react-native-plaid-link-sdk/react-native-plaid-link-sdk.podspec
-+++ b/node_modules/react-native-plaid-link-sdk/react-native-plaid-link-sdk.podspec
-@@ -2,6 +2,8 @@ require 'json'
-
- package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
-
-+fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
-+
- Pod::Spec.new do |s|
- s.name = package['name']
- s.version = package['version']
-@@ -13,8 +15,13 @@ Pod::Spec.new do |s|
- s.platform = :ios, "14.0"
-
- s.source = { :git => "https://github.com/plaid/react-native-plaid-link-sdk.git", :tag => "v#{s.version}" }
-- s.source_files = "ios/*.{h,m,swift}"
-+ s.source_files = "ios/**/*.{h,m,mm,swift}"
-+
-+ if fabric_enabled
-+ install_modules_dependencies(s)
-+ else
-+ s.dependency "React-Core"
-+ end
-
-- s.dependency 'React-Core'
- s.dependency 'Plaid', '~> 5.2.0'
- end
-diff --git a/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/EmbeddedLinkView.tsx b/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/EmbeddedLinkView.tsx
-new file mode 100644
-index 0000000..0243de2
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/EmbeddedLinkView.tsx
-@@ -0,0 +1,95 @@
-+import React from 'react';
-+import { StyleProp, ViewStyle } from 'react-native';
-+import NativeEmbeddedLinkView from './NativeEmbeddedLinkView';
-+import {
-+ LinkSuccessListener,
-+ LinkSuccess,
-+ LinkExitListener,
-+ LinkExit,
-+ LinkIOSPresentationStyle,
-+ LinkOnEventListener,
-+ LinkEvent,
-+ LinkEventName,
-+ LinkEventMetadata,
-+ LinkError,
-+ LinkExitMetadata,
-+ LinkSuccessMetadata,
-+} from '../Types';
-+
-+type EmbeddedLinkProps = {
-+ token: String,
-+ iOSPresentationStyle: LinkIOSPresentationStyle,
-+ onEvent: LinkOnEventListener | undefined,
-+ onSuccess: LinkSuccessListener,
-+ onExit: LinkExitListener | undefined,
-+ style: StyleProp | undefined,
-+}
-+
-+class EmbeddedEvent implements LinkEvent {
-+ eventName: LinkEventName;
-+ metadata: LinkEventMetadata;
-+
-+ constructor(event: any) {
-+ this.eventName = event.eventName
-+ this.metadata = event.metadata
-+ }
-+}
-+
-+class EmbeddedExit implements LinkExit {
-+ error: LinkError | undefined;
-+ metadata: LinkExitMetadata;
-+
-+ constructor(event: any) {
-+ this.error = event.error;
-+ this.metadata = event.metadata;
-+ }
-+}
-+
-+class EmbeddedSuccess implements LinkSuccess {
-+ publicToken: string;
-+ metadata: LinkSuccessMetadata;
-+
-+ constructor(event: any) {
-+ this.publicToken = event.publicToken;
-+ this.metadata = event.metadata;
-+ }
-+}
-+
-+export const EmbeddedLinkView: React.FC = (props) => {
-+
-+ const {token, iOSPresentationStyle, onEvent, onSuccess, onExit, style} = props;
-+
-+ const onEmbeddedEvent = (event: any) => {
-+
-+ switch (event.nativeEvent.embeddedEventName) {
-+ case 'onSuccess': {
-+ if (!onSuccess) { return; }
-+ const embeddedSuccess = new EmbeddedSuccess(event.nativeEvent);
-+ onSuccess(embeddedSuccess);
-+ break;
-+ }
-+ case 'onExit': {
-+ if (!onExit) {return; }
-+ const embeddedExit = new EmbeddedExit(event.nativeEvent);
-+ onExit(embeddedExit);
-+ break;
-+ }
-+ case 'onEvent': {
-+ if (!onEvent) { return; }
-+ const embeddedEvent = new EmbeddedEvent(event.nativeEvent);
-+ onEvent(embeddedEvent);
-+ break;
-+ }
-+ default: {
-+ return;
-+ }
-+ }
-+ }
-+
-+ return
-+};
-\ No newline at end of file
-diff --git a/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/EmbeddedLinkView.web.tsx b/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/EmbeddedLinkView.web.tsx
-new file mode 100644
-index 0000000..7a71609
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/EmbeddedLinkView.web.tsx
-@@ -0,0 +1,5 @@
-+// EmbeddedLinkView.web.tsx is a shim file which causes web bundlers to ignore the EmbeddedLinkView.tsx file
-+// which imports requireNativeComponent (causing a runtime error with react-native-web).
-+// Ref - https://github.com/plaid/react-native-plaid-link-sdk/issues/564
-+import React from 'react';
-+export const EmbeddedLinkView = () => null;
-diff --git a/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/NativeEmbeddedLinkView.tsx b/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/NativeEmbeddedLinkView.tsx
-new file mode 100644
-index 0000000..da05fb1
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/EmbeddedLink/NativeEmbeddedLinkView.tsx
-@@ -0,0 +1,9 @@
-+import { requireNativeComponent } from 'react-native';
-+
-+// Error "Tried to register two views with the same name PLKEmbeddedView"
-+// will be thrown during hot reload when any change is made to the
-+// file that is calling this requireNativeComponent('PLKEmbeddedView') call.
-+// Leaving this in its own file resolves this issue.
-+const NativeEmbeddedLinkView = requireNativeComponent('PLKEmbeddedView');
-+
-+export default NativeEmbeddedLinkView;
-\ No newline at end of file
-diff --git a/node_modules/react-native-plaid-link-sdk/src/PlaidLink.tsx b/node_modules/react-native-plaid-link-sdk/src/PlaidLink.tsx
-new file mode 100644
-index 0000000..b35c06f
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/PlaidLink.tsx
-@@ -0,0 +1,117 @@
-+import React, { useEffect } from 'react';
-+import { NativeEventEmitter, Platform, TouchableOpacity } from 'react-native';
-+import {
-+ LinkError,
-+ LinkEventListener,
-+ LinkExit,
-+ LinkIOSPresentationStyle,
-+ LinkLogLevel,
-+ LinkSuccess,
-+ PlaidLinkComponentProps,
-+ PlaidLinkProps,
-+} from './Types';
-+import RNLinksdkAndroid from './fabric/NativePlaidLinkModuleAndroid';
-+import RNLinksdkiOS from './fabric/NativePlaidLinkModuleiOS';
-+
-+const RNLinksdk = (Platform.OS === 'android' ? RNLinksdkAndroid : RNLinksdkiOS) ?? undefined;
-+
-+/**
-+ * A hook that registers a listener on the Plaid emitter for the 'onEvent' type.
-+ * The listener is cleaned up when this view is unmounted
-+ *
-+ * @param linkEventListener the listener to call
-+ */
-+export const usePlaidEmitter = (linkEventListener: LinkEventListener) => {
-+ useEffect(() => {
-+ const emitter = new NativeEventEmitter(RNLinksdk);
-+ const listener = emitter.addListener('onEvent', linkEventListener);
-+ // Clean up after this effect:
-+ return function cleanup() {
-+ listener.remove();
-+ };
-+ }, []);
-+};
-+
-+export const openLink = async (props: PlaidLinkProps) => {
-+ let config = props.tokenConfig;
-+ let noLoadingState = config.noLoadingState ?? false;
-+
-+ if (Platform.OS === 'android') {
-+ if (RNLinksdkAndroid === null) {
-+ throw new Error('[react-native-plaid-link-sdk] RNLinksdkAndroid is not defined');
-+ }
-+
-+ RNLinksdkAndroid.startLinkActivityForResult(
-+ config.token,
-+ noLoadingState,
-+ config.logLevel ?? LinkLogLevel.ERROR,
-+ // @ts-ignore we use Object type in the spec file as it maps to NSDictionary and ReadableMap
-+ (result: LinkSuccess) => {
-+ if (props.onSuccess != null) {
-+ props.onSuccess(result);
-+ }
-+ },
-+ (result: LinkExit) => {
-+ if (props.onExit != null) {
-+ if (result.error != null && result.error.displayMessage != null) {
-+ //TODO(RNSDK-118): Remove errorDisplayMessage field in next major update.
-+ result.error.errorDisplayMessage = result.error.displayMessage;
-+ }
-+ props.onExit(result);
-+ }
-+ },
-+ );
-+ } else {
-+ if (RNLinksdkiOS === null) {
-+ throw new Error('[react-native-plaid-link-sdk] RNLinksdkiOS is not defined');
-+ }
-+
-+ RNLinksdkiOS.create(config.token, noLoadingState);
-+
-+ let presentFullScreen =
-+ props.iOSPresentationStyle == LinkIOSPresentationStyle.FULL_SCREEN;
-+
-+ RNLinksdkiOS.open(
-+ presentFullScreen,
-+ // @ts-ignore we use Object type in the spec file as it maps to NSDictionary and ReadableMap
-+ (result: LinkSuccess) => {
-+ if (props.onSuccess != null) {
-+ props.onSuccess(result);
-+ }
-+ },
-+ (error: LinkError, result: LinkExit) => {
-+ if (props.onExit != null) {
-+ if (error) {
-+ var data = result || {};
-+ data.error = error;
-+ props.onExit(data);
-+ } else {
-+ props.onExit(result);
-+ }
-+ }
-+ },
-+ );
-+ }
-+};
-+
-+export const dismissLink = () => {
-+ if (Platform.OS === 'ios') {
-+ if (RNLinksdkiOS === null) {
-+ throw new Error('[react-native-plaid-link-sdk] RNLinksdkiOS is not defined');
-+ }
-+
-+ RNLinksdkiOS.dismiss();
-+ }
-+};
-+
-+export const PlaidLink = (props: PlaidLinkComponentProps) => {
-+ function onPress() {
-+ props.onPress?.();
-+ openLink(props);
-+ }
-+
-+ return (
-+ // @ts-ignore some types directories misconfiguration
-+ {props.children}
-+ );
-+};
-diff --git a/node_modules/react-native-plaid-link-sdk/src/Types.ts b/node_modules/react-native-plaid-link-sdk/src/Types.ts
-new file mode 100644
-index 0000000..a7d30c6
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/Types.ts
-@@ -0,0 +1,550 @@
-+interface CommonPlaidLinkOptions {
-+ logLevel?: LinkLogLevel;
-+ extras?: Record;
-+}
-+
-+export type LinkTokenConfiguration = (CommonPlaidLinkOptions & {
-+ token: string;
-+ // A `Bool` indicating that Link should skip displaying a loading animation until the Link UI is fully loaded.
-+ // This can be used to display custom loading UI while Link content is loading (and will skip any initial loading UI in Link).
-+ // Note: Dismiss custom loading UI on the OPEN & EXIT events.
-+ //
-+ // Note: This should be set to `true` when setting the `eu_config.headless` field in /link/token/create requests to `true`.
-+ // For reference, see https://plaid.com/docs/api/tokens/#link-token-create-request-eu-config-headless
-+ noLoadingState?: boolean;
-+});
-+
-+export enum LinkLogLevel {
-+ DEBUG="debug",
-+ INFO="info",
-+ WARN="warn",
-+ ERROR="error",
-+}
-+
-+export enum PlaidEnvironment {
-+ PRODUCTION = 'production',
-+ DEVELOPMENT = 'development',
-+ SANDBOX = 'sandbox',
-+}
-+
-+export enum PlaidProduct {
-+ ASSETS="assets",
-+ AUTH="auth",
-+ DEPOSIT_SWITCH="deposit_switch",
-+ IDENTITY="identity",
-+ INCOME="income",
-+ INVESTMENTS="investments",
-+ LIABILITIES="liabilities",
-+ LIABILITIES_REPORT="liabilities_report",
-+ PAYMENT_INITIATION="payment_initiation",
-+ TRANSACTIONS="transactions",
-+}
-+
-+export enum LinkAccountType {
-+ CREDIT = 'credit',
-+ DEPOSITORY = 'depository',
-+ INVESTMENT = 'investment',
-+ LOAN = 'loan',
-+ OTHER = 'other',
-+}
-+
-+export enum LinkAccountSubtypes {
-+ ALL = 'all',
-+ CREDIT_CARD = 'credit card',
-+ PAYPAL = 'paypal',
-+ AUTO = 'auto',
-+ BUSINESS = 'business',
-+ COMMERCIAL = 'commercial',
-+ CONSTRUCTION = 'construction',
-+ CONSUMER = 'consumer',
-+ HOME_EQUITY = 'home equity',
-+ LINE_OF_CREDIT = 'line of credit',
-+ LOAN = 'loan',
-+ MORTGAGE = 'mortgage',
-+ OVERDRAFT = 'overdraft',
-+ STUDENT = 'student',
-+ CASH_MANAGEMENT = 'cash management',
-+ CD = 'cd',
-+ CHECKING = 'checking',
-+ EBT = 'ebt',
-+ HSA = 'hsa',
-+ MONEY_MARKET = 'money market',
-+ PREPAID = 'prepaid',
-+ SAVINGS = 'savings',
-+ FOUR_0_1_A = '401a',
-+ FOUR_0_1_K = '401k',
-+ FOUR_0_3_B = '403B',
-+ FOUR_5_7_B = '457b',
-+ FIVE_2_9 = '529',
-+ BROKERAGE = 'brokerage',
-+ CASH_ISA = 'cash isa',
-+ EDUCATION_SAVINGS_ACCOUNT = 'education savings account',
-+ FIXED_ANNUNITY = 'fixed annuity',
-+ GIC = 'gic',
-+ HEALTH_REIMBURSEMENT_ARRANGEMENT = 'health reimbursement arrangement',
-+ IRA = 'ira',
-+ ISA = 'isa',
-+ KEOGH = 'keogh',
-+ LIF = 'lif',
-+ LIRA = 'lira',
-+ LRIF = 'lrif',
-+ LRSP = 'lrsp',
-+ MUTUAL_FUND = 'mutual fund',
-+ NON_TAXABLE_BROKERAGE_ACCOUNT = 'non-taxable brokerage account',
-+ PENSION = 'pension',
-+ PLAN = 'plan',
-+ PRIF = 'prif',
-+ PROFIT_SHARING_PLAN = 'profit sharing plan',
-+ RDSP = 'rdsp',
-+ RESP = 'resp',
-+ RETIREMENT = 'retirement',
-+ RLIF = 'rlif',
-+ ROTH_401K = 'roth 401k',
-+ ROTH = 'roth',
-+ RRIF = 'rrif',
-+ RRSP = 'rrsp',
-+ SARSEP = 'sarsep',
-+ SEP_IRA = 'sep ira',
-+ SIMPLE_IRA = 'simple ira',
-+ SIPP = 'sipp',
-+ STOCK_PLAN = 'stock plan',
-+ TFSA = 'tfsa',
-+ THRIFT_SAVINGS_PLAN = 'thrift savings plan',
-+ TRUST = 'trust',
-+ UGMA = 'ugma',
-+ UTMA = 'utma',
-+ VARIABLE_ANNUITY = 'variable annuity'
-+}
-+
-+export interface LinkAccountSubtype {
-+}
-+
-+export class LinkAccountSubtypeCredit implements LinkAccountSubtype {
-+ public static readonly ALL = new LinkAccountSubtypeCredit(LinkAccountType.CREDIT, LinkAccountSubtypes.ALL);
-+ public static readonly CREDIT_CARD = new LinkAccountSubtypeCredit(LinkAccountType.CREDIT, LinkAccountSubtypes.CREDIT_CARD);
-+ public static readonly PAYPAL = new LinkAccountSubtypeCredit(LinkAccountType.CREDIT, LinkAccountSubtypes.PAYPAL);
-+
-+ private constructor(public readonly type: LinkAccountType, public readonly subtype: LinkAccountSubtype) { }
-+}
-+
-+export class LinkAccountSubtypeDepository implements LinkAccountSubtype {
-+ public static readonly ALL = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.ALL);
-+ public static readonly CASH_MANAGEMENT = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.CASH_MANAGEMENT);
-+ public static readonly CD = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.CD);
-+ public static readonly CHECKING = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.CHECKING);
-+ public static readonly EBT = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.EBT);
-+ public static readonly HSA = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.HSA);
-+ public static readonly MONEY_MARKET = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.MONEY_MARKET);
-+ public static readonly PAYPAL = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.PAYPAL);
-+ public static readonly PREPAID = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.PREPAID);
-+ public static readonly SAVINGS = new LinkAccountSubtypeDepository(LinkAccountType.DEPOSITORY, LinkAccountSubtypes.SAVINGS);
-+
-+ private constructor(public readonly type: LinkAccountType, public readonly subtype: LinkAccountSubtype) { }
-+}
-+
-+export class LinkAccountSubtypeInvestment implements LinkAccountSubtype {
-+ public static readonly ALL = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ALL);
-+ public static readonly BROKERAGE = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.BROKERAGE);
-+ public static readonly CASH_ISA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.CASH_ISA);
-+ public static readonly EDUCATION_SAVINGS_ACCOUNT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.EDUCATION_SAVINGS_ACCOUNT);
-+ public static readonly FIXED_ANNUNITY = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FIXED_ANNUNITY);
-+ public static readonly GIC = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.GIC);
-+ public static readonly HEALTH_REIMBURSEMENT_ARRANGEMENT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.HEALTH_REIMBURSEMENT_ARRANGEMENT);
-+ public static readonly HSA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.HSA);
-+ public static readonly INVESTMENT_401A = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_0_1_A);
-+ public static readonly INVESTMENT_401K = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_0_1_K);
-+ public static readonly INVESTMENT_403B = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_0_3_B);
-+ public static readonly INVESTMENT_457B = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FOUR_5_7_B);
-+ public static readonly INVESTMENT_529 = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.FIVE_2_9);
-+ public static readonly IRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.IRA);
-+ public static readonly ISA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ISA);
-+ public static readonly KEOGH = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.KEOGH);
-+ public static readonly LIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LIF);
-+ public static readonly LIRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LIRA);
-+ public static readonly LRIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LRIF);
-+ public static readonly LRSP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.LRSP);
-+ public static readonly MUTUAL_FUND = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.MUTUAL_FUND);
-+ public static readonly NON_TAXABLE_BROKERAGE_ACCOUNT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.NON_TAXABLE_BROKERAGE_ACCOUNT);
-+ public static readonly PENSION = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PENSION);
-+ public static readonly PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PLAN);
-+ public static readonly PRIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PRIF);
-+ public static readonly PROFIT_SHARING_PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.PROFIT_SHARING_PLAN);
-+ public static readonly RDSP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RDSP);
-+ public static readonly RESP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RESP);
-+ public static readonly RETIREMENT = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RETIREMENT);
-+ public static readonly RLIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RLIF);
-+ public static readonly ROTH = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ROTH);
-+ public static readonly ROTH_401K = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.ROTH_401K);
-+ public static readonly RRIF = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RRIF);
-+ public static readonly RRSP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.RRSP);
-+ public static readonly SARSEP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SARSEP);
-+ public static readonly SEP_IRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SEP_IRA);
-+ public static readonly SIMPLE_IRA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SIMPLE_IRA);
-+ public static readonly SIIP = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.SIPP);
-+ public static readonly STOCK_PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.STOCK_PLAN);
-+ public static readonly TFSA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.TFSA);
-+ public static readonly THRIFT_SAVINGS_PLAN = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.THRIFT_SAVINGS_PLAN);
-+ public static readonly TRUST = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.TRUST);
-+ public static readonly UGMA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.UGMA);
-+ public static readonly UTMA = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.UTMA);
-+ public static readonly VARIABLE_ANNUITY = new LinkAccountSubtypeInvestment(LinkAccountType.INVESTMENT, LinkAccountSubtypes.VARIABLE_ANNUITY);
-+
-+ private constructor(public readonly type: LinkAccountType, public readonly subtype: LinkAccountSubtype) { }
-+}
-+
-+export class LinkAccountSubtypeLoan implements LinkAccountSubtype {
-+ public static readonly ALL = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.ALL);
-+ public static readonly AUTO = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.AUTO);
-+ public static readonly BUSINESS = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.BUSINESS);
-+ public static readonly COMMERCIAL = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.COMMERCIAL);
-+ public static readonly CONSTRUCTION = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.CONSTRUCTION);
-+ public static readonly CONSUMER = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.CONSUMER);
-+ public static readonly HOME_EQUITY = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.HOME_EQUITY);
-+ public static readonly LINE_OF_CREDIT = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.LINE_OF_CREDIT);
-+ public static readonly LOAN = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.LOAN);
-+ public static readonly MORTGAGE = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.MORTGAGE);
-+ public static readonly OVERDRAFT = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.OVERDRAFT);
-+ public static readonly STUDENT = new LinkAccountSubtypeLoan(LinkAccountType.CREDIT, LinkAccountSubtypes.STUDENT);
-+
-+ private constructor(public readonly type: LinkAccountType, public readonly subtype: LinkAccountSubtype) { }
-+}
-+
-+export class LinkAccountSubtypeUnknown implements LinkAccountSubtype {
-+ constructor(public readonly type: string, public readonly subtype: string) { }
-+}
-+
-+export interface LinkSuccess {
-+ publicToken: string;
-+ metadata: LinkSuccessMetadata;
-+}
-+
-+export interface LinkSuccessMetadata {
-+ institution?: LinkInstitution;
-+ accounts: LinkAccount[];
-+ linkSessionId: string;
-+ metadataJson?: string;
-+}
-+
-+export interface LinkAccount {
-+ id: string;
-+ name?: string;
-+ mask?: string;
-+ type: LinkAccountType;
-+ subtype: LinkAccountSubtype;
-+ verificationStatus?: LinkAccountVerificationStatus;
-+}
-+
-+export enum LinkAccountVerificationStatus {
-+ PENDING_AUTOMATIC_VERIFICATION = 'pending_automatic_verification',
-+ PENDING_MANUAL_VERIFICATION = 'pending_manual_verification',
-+ MANUALLY_VERIFIED = 'manually_verified',
-+}
-+
-+export interface LinkInstitution {
-+ id: string;
-+ name: string;
-+}
-+
-+export interface LinkExit {
-+ error?: LinkError;
-+ metadata: LinkExitMetadata;
-+}
-+
-+export interface LinkExitMetadata {
-+ status?: LinkExitMetadataStatus;
-+ institution?: LinkInstitution;
-+ linkSessionId: string;
-+ requestId: string;
-+ metadataJson?: string;
-+}
-+
-+export enum LinkExitMetadataStatus {
-+ CONNECTED = 'connected',
-+ CHOOSE_DEVICE = 'choose_device',
-+ REQUIRES_ACCOUNT_SELECTION = 'requires_account_selection',
-+ REQUIRES_CODE = 'requires_code',
-+ REQUIRES_CREDENTIALS = 'requires_credentials',
-+ REQUIRES_EXTERNAL_ACTION = 'requires_external_action',
-+ REQUIRES_OAUTH = 'requires_oauth',
-+ REQUIRES_QUESTIONS = 'requires_questions',
-+ REQUIRES_RECAPTCHA = 'requires_recaptcha',
-+ REQUIRES_SELECTIONS = 'requires_selections',
-+ REQUIRES_DEPOSIT_SWITCH_ALLOCATION_CONFIGURATION = 'requires_deposit_switch_allocation_configuration',
-+ REQUIRES_DEPOSIT_SWITCH_ALLOCATION_SELECTION = 'requires_deposit_switch_allocation_selection',
-+}
-+
-+export interface LinkError {
-+ errorCode: LinkErrorCode;
-+ errorType: LinkErrorType;
-+ errorMessage: string;
-+ /** @deprecated DO NOT USE, data not guaranteed. Use `displayMessage` instead */
-+ errorDisplayMessage?: string;
-+ displayMessage?: string;
-+ errorJson?: string;
-+}
-+
-+export enum LinkErrorCode {
-+ // ITEM_ERROR
-+ INVALID_CREDENTIALS = "INVALID_CREDENTIALS",
-+ INVALID_MFA = "INVALID_MFA",
-+ ITEM_LOGIN_REQUIRED = "ITEM_LOGIN_REQUIRED",
-+ INSUFFICIENT_CREDENTIALS = "INSUFFICIENT_CREDENTIALS",
-+ ITEM_LOCKED = "ITEM_LOCKED",
-+ USER_SETUP_REQUIRED = "USER_SETUP_REQUIRED",
-+ MFA_NOT_SUPPORTED = "MFA_NOT_SUPPORTED",
-+ INVALID_SEND_METHOD = "INVALID_SEND_METHOD",
-+ NO_ACCOUNTS = "NO_ACCOUNTS",
-+ ITEM_NOT_SUPPORTED = "ITEM_NOT_SUPPORTED",
-+ TOO_MANY_VERIFICATION_ATTEMPTS = "TOO_MANY_VERIFICATION_ATTEMPTS",
-+
-+ INVALD_UPDATED_USERNAME = "INVALD_UPDATED_USERNAME",
-+ INVALID_UPDATED_USERNAME = "INVALID_UPDATED_USERNAME",
-+
-+ ITEM_NO_ERROR = "ITEM_NO_ERROR",
-+ item_no_error = "item-no-error",
-+ NO_AUTH_ACCOUNTS = "NO_AUTH_ACCOUNTS",
-+ NO_INVESTMENT_ACCOUNTS = "NO_INVESTMENT_ACCOUNTS",
-+ NO_INVESTMENT_AUTH_ACCOUNTS = "NO_INVESTMENT_AUTH_ACCOUNTS",
-+ NO_LIABILITY_ACCOUNTS = "NO_LIABILITY_ACCOUNTS",
-+ PRODUCTS_NOT_SUPPORTED = "PRODUCTS_NOT_SUPPORTED",
-+ ITEM_NOT_FOUND = "ITEM_NOT_FOUND",
-+ ITEM_PRODUCT_NOT_READY = "ITEM_PRODUCT_NOT_READY",
-+
-+ // INSTITUTION_ERROR
-+ INSTITUTION_DOWN = "INSTITUTION_DOWN",
-+ INSTITUTION_NOT_RESPONDING = "INSTITUTION_NOT_RESPONDING",
-+ INSTITUTION_NOT_AVAILABLE = "INSTITUTION_NOT_AVAILABLE",
-+ INSTITUTION_NO_LONGER_SUPPORTED = "INSTITUTION_NO_LONGER_SUPPORTED",
-+
-+ // API_ERROR
-+ INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR",
-+ PLANNED_MAINTENANCE = "PLANNED_MAINTENANCE",
-+
-+ // ASSET_REPORT_ERROR
-+ PRODUCT_NOT_ENABLED = "PRODUCT_NOT_ENABLED",
-+ DATA_UNAVAILABLE = "DATA_UNAVAILABLE",
-+ ASSET_PRODUCT_NOT_READY = "ASSET_PRODUCT_NOT_READY",
-+ ASSET_REPORT_GENERATION_FAILED = "ASSET_REPORT_GENERATION_FAILED",
-+ INVALID_PARENT = "INVALID_PARENT",
-+ INSIGHTS_NOT_ENABLED = "INSIGHTS_NOT_ENABLED",
-+ INSIGHTS_PREVIOUSLY_NOT_ENABLED = "INSIGHTS_PREVIOUSLY_NOT_ENABLED",
-+
-+ // BANK_TRANSFER_ERROR
-+ BANK_TRANSFER_LIMIT_EXCEEDED = "BANK_TRANSFER_LIMIT_EXCEEDED",
-+ BANK_TRANSFER_MISSING_ORIGINATION_ACCOUNT = "BANK_TRANSFER_MISSING_ORIGINATION_ACCOUNT",
-+ BANK_TRANSFER_INVALID_ORIGINATION_ACCOUNT = "BANK_TRANSFER_INVALID_ORIGINATION_ACCOUNT",
-+ BANK_TRANSFER_ACCOUNT_BLOCKED = "BANK_TRANSFER_ACCOUNT_BLOCKED",
-+ BANK_TRANSFER_INSUFFICIENT_FUNDS = "BANK_TRANSFER_INSUFFICIENT_FUNDS",
-+ BANK_TRANSFER_NOT_CANCELLABLE = "BANK_TRANSFER_NOT_CANCELLABLE",
-+ BANK_TRANSFER_UNSUPPORTED_ACCOUNT_TYPE = "BANK_TRANSFER_UNSUPPORTED_ACCOUNT_TYPE",
-+ BANK_TRANSFER_UNSUPPORTED_ENVIRONMENT = "BANK_TRANSFER_UNSUPPORTED_ENVIRONMENT",
-+
-+ // SANDBOX_ERROR
-+ SANDBOX_PRODUCT_NOT_ENABLED = "SANDBOX_PRODUCT_NOT_ENABLED",
-+ SANDBOX_WEBHOOK_INVALID = "SANDBOX_WEBHOOK_INVALID",
-+ SANDBOX_BANK_TRANSFER_EVENT_TRANSITION_INVALID = "SANDBOX_BANK_TRANSFER_EVENT_TRANSITION_INVALID",
-+
-+ // INVALID_REQUEST
-+ MISSING_FIELDS = "MISSING_FIELDS",
-+ UNKNOWN_FIELDS = "UNKNOWN_FIELDS",
-+ INVALID_FIELD = "INVALID_FIELD",
-+ INCOMPATIBLE_API_VERSION = "INCOMPATIBLE_API_VERSION",
-+ INVALID_BODY = "INVALID_BODY",
-+ INVALID_HEADERS = "INVALID_HEADERS",
-+ NOT_FOUND = "NOT_FOUND",
-+ NO_LONGER_AVAILABLE = "NO_LONGER_AVAILABLE",
-+ SANDBOX_ONLY = "SANDBOX_ONLY",
-+ INVALID_ACCOUNT_NUMBER = "INVALID_ACCOUNT_NUMBER",
-+
-+ // INVALID_INPUT
-+ // From above ITEM_LOGIN_REQUIRED = "INVALID_CREDENTIALS",
-+ INCORRECT_DEPOSIT_AMOUNTS = "INCORRECT_DEPOSIT_AMOUNTS",
-+ UNAUTHORIZED_ENVIRONMENT = "UNAUTHORIZED_ENVIRONMENT",
-+ INVALID_PRODUCT = "INVALID_PRODUCT",
-+ UNAUTHORIZED_ROUTE_ACCESS = "UNAUTHORIZED_ROUTE_ACCESS",
-+ DIRECT_INTEGRATION_NOT_ENABLED = "DIRECT_INTEGRATION_NOT_ENABLED",
-+ INVALID_API_KEYS = "INVALID_API_KEYS",
-+ INVALID_ACCESS_TOKEN = "INVALID_ACCESS_TOKEN",
-+ INVALID_PUBLIC_TOKEN = "INVALID_PUBLIC_TOKEN",
-+ INVALID_LINK_TOKEN = "INVALID_LINK_TOKEN",
-+ INVALID_PROCESSOR_TOKEN = "INVALID_PROCESSOR_TOKEN",
-+ INVALID_AUDIT_COPY_TOKEN = "INVALID_AUDIT_COPY_TOKEN",
-+ INVALID_ACCOUNT_ID = "INVALID_ACCOUNT_ID",
-+ MICRODEPOSITS_ALREADY_VERIFIED = "MICRODEPOSITS_ALREADY_VERIFIED",
-+
-+ // INVALID_RESULT
-+ PLAID_DIRECT_ITEM_IMPORT_RETURNED_INVALID_MFA = "PLAID_DIRECT_ITEM_IMPORT_RETURNED_INVALID_MFA",
-+
-+ // RATE_LIMIT_EXCEEDED
-+ ACCOUNTS_LIMIT = "ACCOUNTS_LIMIT",
-+ ADDITION_LIMIT = "ADDITION_LIMIT",
-+ AUTH_LIMIT = "AUTH_LIMIT",
-+ BALANCE_LIMIT = "BALANCE_LIMIT",
-+ IDENTITY_LIMIT = "IDENTITY_LIMIT",
-+ ITEM_GET_LIMIT = "ITEM_GET_LIMIT",
-+ RATE_LIMIT = "RATE_LIMIT",
-+ TRANSACTIONS_LIMIT = "TRANSACTIONS_LIMIT",
-+
-+ // RECAPTCHA_ERROR
-+ RECAPTCHA_REQUIRED = "RECAPTCHA_REQUIRED",
-+ RECAPTCHA_BAD = "RECAPTCHA_BAD",
-+
-+ // OAUTH_ERROR
-+ INCORRECT_OAUTH_NONCE = "INCORRECT_OAUTH_NONCE",
-+ OAUTH_STATE_ID_ALREADY_PROCESSED = "OAUTH_STATE_ID_ALREADY_PROCESSED",
-+}
-+
-+export enum LinkErrorType {
-+ BANK_TRANSFER = 'BANK_TRANSFER_ERROR',
-+ INVALID_REQUEST = 'INVALID_REQUEST',
-+ INVALID_RESULT = 'INVALID_RESULT',
-+ INVALID_INPUT = 'INVALID_INPUT',
-+ INSTITUTION_ERROR = 'INSTITUTION_ERROR',
-+ RATE_LIMIT_EXCEEDED = 'RATE_LIMIT_EXCEEDED',
-+ API_ERROR = 'API_ERROR',
-+ ITEM_ERROR = 'ITEM_ERROR',
-+ AUTH_ERROR = 'AUTH_ERROR',
-+ ASSET_REPORT_ERROR = 'ASSET_REPORT_ERROR',
-+ SANDBOX_ERROR = 'SANDBOX_ERROR',
-+ RECAPTCHA_ERROR = 'RECAPTCHA_ERROR',
-+ OAUTH_ERROR = 'OAUTH_ERROR',
-+}
-+
-+export type LinkEventListener = (linkEvent: LinkEvent) => void
-+
-+export interface LinkEvent {
-+ eventName: LinkEventName;
-+ metadata: LinkEventMetadata;
-+}
-+
-+export interface LinkEventMetadata {
-+ accountNumberMask?: string;
-+ linkSessionId: string;
-+ mfaType?: string;
-+ requestId?: string;
-+ viewName: LinkEventViewName;
-+ errorCode?: string;
-+ errorMessage?: string;
-+ errorType?: string;
-+ exitStatus?: string;
-+ institutionId?: string;
-+ institutionName?: string;
-+ institutionSearchQuery?: string;
-+ isUpdateMode?: string;
-+ matchReason?: string;
-+ // see possible values for selection at https://plaid.com/docs/link/web/#link-web-onevent-selection
-+ selection?: null | string;
-+ timestamp: string;
-+}
-+
-+export enum LinkEventName {
-+ BANK_INCOME_INSIGHTS_COMPLETED = "BANK_INCOME_INSIGHTS_COMPLETED",
-+ CLOSE_OAUTH = 'CLOSE_OAUTH',
-+ ERROR = 'ERROR',
-+ EXIT = 'EXIT',
-+ FAIL_OAUTH = 'FAIL_OAUTH',
-+ HANDOFF = 'HANDOFF',
-+ IDENTITY_VERIFICATION_START_STEP = 'IDENTITY_VERIFICATION_START_STEP',
-+ IDENTITY_VERIFICATION_PASS_STEP = 'IDENTITY_VERIFICATION_PASS_STEP',
-+ IDENTITY_VERIFICATION_FAIL_STEP = 'IDENTITY_VERIFICATION_FAIL_STEP',
-+ IDENTITY_VERIFICATION_PENDING_REVIEW_STEP = 'IDENTITY_VERIFICATION_PENDING_REVIEW_STEP',
-+ IDENTITY_VERIFICATION_PENDING_REVIEW_SESSION = 'IDENTITY_VERIFICATION_PENDING_REVIEW_SESSION',
-+ IDENTITY_VERIFICATION_CREATE_SESSION = 'IDENTITY_VERIFICATION_CREATE_SESSION',
-+ IDENTITY_VERIFICATION_RESUME_SESSION = 'IDENTITY_VERIFICATION_RESUME_SESSION',
-+ IDENTITY_VERIFICATION_PASS_SESSION = 'IDENTITY_VERIFICATION_PASS_SESSION',
-+ IDENTITY_VERIFICATION_FAIL_SESSION = 'IDENTITY_VERIFICATION_FAIL_SESSION',
-+ IDENTITY_VERIFICATION_OPEN_UI = 'IDENTITY_VERIFICATION_OPEN_UI',
-+ IDENTITY_VERIFICATION_RESUME_UI = 'IDENTITY_VERIFICATION_RESUME_UI',
-+ IDENTITY_VERIFICATION_CLOSE_UI = 'IDENTITY_VERIFICATION_CLOSE_UI',
-+ MATCHED_CONSENT = 'MATCHED_CONSENT',
-+ MATCHED_SELECT_INSTITUTION = 'MATCHED_SELECT_INSTITUTION',
-+ MATCHED_SELECT_VERIFY_METHOD = 'MATCHED_SELECT_VERIFY_METHOD',
-+ OPEN = 'OPEN',
-+ OPEN_MY_PLAID = 'OPEN_MY_PLAID',
-+ OPEN_OAUTH = 'OPEN_OAUTH',
-+ SEARCH_INSTITUTION = 'SEARCH_INSTITUTION',
-+ SELECT_DEGRADED_INSTITUTION = 'SELECT_DEGRADED_INSTITUTION',
-+ SELECT_DOWN_INSTITUTION = 'SELECT_DOWN_INSTITUTION',
-+ SELECT_FILTERED_INSTITUTION = 'SELECT_FILTERED_INSTITUTION',
-+ SELECT_INSTITUTION = 'SELECT_INSTITUTION',
-+ SELECT_BRAND = 'SELECT_BRAND',
-+ SELECT_AUTH_TYPE = 'SELECT_AUTH_TYPE',
-+ SUBMIT_ACCOUNT_NUMBER = 'SUBMIT_ACCOUNT_NUMBER',
-+ SUBMIT_DOCUMENTS = 'SUBMIT_DOCUMENTS',
-+ SUBMIT_DOCUMENTS_SUCCESS = 'SUBMIT_DOCUMENTS_SUCCESS',
-+ SUBMIT_DOCUMENTS_ERROR = 'SUBMIT_DOCUMENTS_ERROR',
-+ SUBMIT_ROUTING_NUMBER = 'SUBMIT_ROUTING_NUMBER',
-+ VIEW_DATA_TYPES = 'VIEW_DATA_TYPES',
-+ SUBMIT_PHONE = 'SUBMIT_PHONE',
-+ SKIP_SUBMIT_PHONE = 'SKIP_SUBMIT_PHONE',
-+ VERIFY_PHONE = 'VERIFY_PHONE',
-+ SUBMIT_CREDENTIALS = 'SUBMIT_CREDENTIALS',
-+ SUBMIT_MFA = 'SUBMIT_MFA',
-+ TRANSITION_VIEW = 'TRANSITION_VIEW',
-+ CONNECT_NEW_INSTITUTION = 'CONNECT_NEW_INSTITUTION',
-+}
-+
-+export enum LinkEventViewName {
-+ ACCEPT_TOS = 'ACCEPT_TOS',
-+ CONNECTED = 'CONNECTED',
-+ CONSENT = 'CONSENT',
-+ CREDENTIAL = 'CREDENTIAL',
-+ DATA_TRANSPARENCY = 'DATA_TRANSPARENCY',
-+ DATA_TRANSPARENCY_CONSENT = 'DATA_TRANSPARENCY_CONSENT',
-+ DOCUMENTARY_VERIFICATION = 'DOCUMENTARY_VERIFICATION',
-+ ERROR = 'ERROR',
-+ EXIT = 'EXIT',
-+ KYC_CHECK = 'KYC_CHECK',
-+ SELFIE_CHECK = 'SELFIE_CHECK',
-+ LOADING = 'LOADING',
-+ MATCHED_CONSENT = 'MATCHED_CONSENT',
-+ MATCHED_CREDENTIAL = 'MATCHED_CREDENTIAL',
-+ MATCHED_MFA = 'MATCHED_MFA',
-+ MFA = 'MFA',
-+ NUMBERS = 'NUMBERS',
-+ NUMBERS_SELECT_INSTITUTION = 'NUMBERS_SELECT_INSTITUTION',
-+ OAUTH = 'OAUTH',
-+ RECAPTCHA = 'RECAPTCHA',
-+ RISK_CHECK = 'RISK_CHECK',
-+ SCREENING = 'SCREENING',
-+ SELECT_ACCOUNT = 'SELECT_ACCOUNT',
-+ SELECT_AUTH_TYPE = 'SELECT_AUTH_TYPE',
-+ SUBMIT_PHONE = 'SUBMIT_PHONE',
-+ VERIFY_PHONE = 'VERIFY_PHONE',
-+ SELECT_SAVED_INSTITUTION = 'SELECT_SAVED_INSTITUTION',
-+ SELECT_SAVED_ACCOUNT = 'SELECT_SAVED_ACCOUNT',
-+ SELECT_BRAND = 'SELECT_BRAND',
-+ SELECT_INSTITUTION = 'SELECT_INSTITUTION',
-+ SUBMIT_DOCUMENTS = 'SUBMIT_DOCUMENTS',
-+ SUBMIT_DOCUMENTS_SUCCESS = 'SUBMIT_DOCUMENTS_SUCCESS',
-+ SUBMIT_DOCUMENTS_ERROR = 'SUBMIT_DOCUMENTS_ERROR',
-+ UPLOAD_DOCUMENTS = 'UPLOAD_DOCUMENTS',
-+ VERIFY_SMS = 'VERIFY_SMS',
-+}
-+
-+/// Methods to present Link on iOS.
-+/// FULL_SCREEN is the converts to UIModalPresentationOverFullScreen on the native side.
-+/// MODAL will use the default presentation style for iOS which is UIModalPresentationAutomatic.
-+export enum LinkIOSPresentationStyle {
-+ FULL_SCREEN = 'FULL_SCREEN',
-+ MODAL = 'MODAL'
-+}
-+
-+export type LinkSuccessListener = (LinkSuccess: LinkSuccess) => void
-+
-+export type LinkExitListener = (LinkExit: LinkExit) => void
-+
-+export type LinkOnEventListener = (LinkEvent: LinkEvent) => void
-+
-+export interface PlaidLinkProps {
-+ tokenConfig: LinkTokenConfiguration
-+ onSuccess: LinkSuccessListener
-+ onExit?: LinkExitListener
-+ iOSPresentationStyle?: LinkIOSPresentationStyle
-+ logLevel?: LinkLogLevel
-+ onPress?(): any
-+}
-+
-+export type PlaidLinkComponentProps = (PlaidLinkProps & {
-+ children: React.ReactNode
-+});
-diff --git a/node_modules/react-native-plaid-link-sdk/src/__tests__/Types.tests.ts b/node_modules/react-native-plaid-link-sdk/src/__tests__/Types.tests.ts
-new file mode 100644
-index 0000000..2dd7a54
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/__tests__/Types.tests.ts
-@@ -0,0 +1,15 @@
-+const Types = require('./../Types');
-+
-+test('test token configuration', () => {
-+ const linkTokenConfiguration = {
-+ token: "test-token",
-+ noLoadingState: false,
-+ logLevel: Types.LinkLogLevel.DEBUG,
-+ extras: null,
-+ };
-+
-+ expect(linkTokenConfiguration.noLoadingState).toBe(false);
-+ expect(linkTokenConfiguration.token).toBe("test-token");
-+ expect(linkTokenConfiguration.logLevel).toBe(Types.LinkLogLevel.DEBUG);
-+ expect(linkTokenConfiguration.extras).toBe(null);
-+});
-\ No newline at end of file
-diff --git a/node_modules/react-native-plaid-link-sdk/src/fabric/NativePlaidLinkModuleAndroid.ts b/node_modules/react-native-plaid-link-sdk/src/fabric/NativePlaidLinkModuleAndroid.ts
-new file mode 100644
-index 0000000..d1e4062
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/fabric/NativePlaidLinkModuleAndroid.ts
-@@ -0,0 +1,20 @@
-+// we use Object type because methods on the native side use NSDictionary and ReadableMap
-+// and we want to stay compatible with those
-+import {TurboModuleRegistry, TurboModule} from 'react-native';
-+import { Int32, UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
-+
-+export interface Spec extends TurboModule {
-+ startLinkActivityForResult(
-+ token: string,
-+ noLoadingState: boolean,
-+ logLevel: string,
-+ onSuccessCallback: (result: UnsafeObject) => void,
-+ onExitCallback: (result: UnsafeObject) => void
-+ ): void;
-+
-+ // those two are here for event emitter methods
-+ addListener(eventName: string): void;
-+ removeListeners(count: Int32): void;
-+}
-+
-+export default TurboModuleRegistry.get('PlaidAndroid');
-diff --git a/node_modules/react-native-plaid-link-sdk/src/fabric/NativePlaidLinkModuleiOS.ts b/node_modules/react-native-plaid-link-sdk/src/fabric/NativePlaidLinkModuleiOS.ts
-new file mode 100644
-index 0000000..d1b3565
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/fabric/NativePlaidLinkModuleiOS.ts
-@@ -0,0 +1,19 @@
-+// we use Object type because methods on the native side use NSDictionary and ReadableMap
-+// and we want to stay compatible with those
-+import {TurboModuleRegistry, TurboModule} from 'react-native';
-+import { Int32, UnsafeObject } from 'react-native/Libraries/Types/CodegenTypes';
-+
-+export interface Spec extends TurboModule {
-+ create(token: string, noLoadingState: boolean): void;
-+ open(
-+ fullScreen: boolean,
-+ onSuccess: (success: UnsafeObject) => void,
-+ onExit: (error: UnsafeObject, result: UnsafeObject) => void,
-+ ): void;
-+ dismiss(): void;
-+ // those two are here for event emitter methods
-+ addListener(eventName: string): void;
-+ removeListeners(count: Int32): void;
-+}
-+
-+export default TurboModuleRegistry.get('RNLinksdk');
-diff --git a/node_modules/react-native-plaid-link-sdk/src/index.ts b/node_modules/react-native-plaid-link-sdk/src/index.ts
-new file mode 100644
-index 0000000..23ef946
---- /dev/null
-+++ b/node_modules/react-native-plaid-link-sdk/src/index.ts
-@@ -0,0 +1,21 @@
-+import {
-+ openLink,
-+ dismissLink,
-+ usePlaidEmitter,
-+ PlaidLink,
-+} from './PlaidLink';
-+
-+export * from './Types';
-+
-+export default PlaidLink;
-+
-+export {
-+ PlaidLink,
-+ openLink,
-+ dismissLink,
-+ usePlaidEmitter,
-+};
-+
-+// Components
-+
-+export { EmbeddedLinkView } from './EmbeddedLink/EmbeddedLinkView';
-\ No newline at end of file
diff --git a/scripts/applyPatches.sh b/scripts/applyPatches.sh
index 9145629015ee..4ce023755258 100755
--- a/scripts/applyPatches.sh
+++ b/scripts/applyPatches.sh
@@ -11,7 +11,7 @@ source "$SCRIPTS_DIR/shellUtils.sh"
function patchPackage {
OS="$(uname)"
if [[ "$OS" == "Darwin" || "$OS" == "Linux" ]]; then
- npx patch-package --error-on-fail
+ npx patch-package --error-on-fail --color=always
else
error "Unsupported OS: $OS"
exit 1
diff --git a/src/CONST.ts b/src/CONST.ts
index 3f141905e84c..201f95ae9f57 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -842,6 +842,8 @@ const CONST = {
IOU: 'iou',
TASK: 'task',
INVOICE: 'invoice',
+ },
+ UNSUPPORTED_TYPE: {
PAYCHECK: 'paycheck',
BILL: 'bill',
},
@@ -2346,6 +2348,8 @@ const CONST = {
POLICY_ID_FROM_PATH: /\/w\/([a-zA-Z0-9]+)(\/|$)/,
SHORT_MENTION: new RegExp(`@[\\w\\-\\+\\'#@]+(?:\\.[\\w\\-\\'\\+]+)*(?![^\`]*\`)`, 'gim'),
+
+ REPORT_ID_FROM_PATH: /\/r\/(\d+)/,
},
PRONOUNS: {
@@ -5229,6 +5233,7 @@ const CONST = {
SUBMIT: 'submit',
APPROVE: 'approve',
PAY: 'pay',
+ EXPORT: 'export',
},
SYNTAX_OPERATORS: {
AND: 'and',
@@ -5308,24 +5313,55 @@ const CONST = {
},
EXCLUDE_FROM_LAST_VISITED_PATH: [SCREENS.NOT_FOUND, SCREENS.SAML_SIGN_IN, SCREENS.VALIDATE_LOGIN] as string[],
-
EMPTY_STATE_MEDIA: {
ANIMATION: 'animation',
ILLUSTRATION: 'illustration',
VIDEO: 'video',
},
-
- UPGRADE_FEATURE_INTRO_MAPPING: [
- {
- id: 'reportFields',
- alias: 'report-fields',
- name: 'Report Fields',
- title: 'workspace.upgrade.reportFields.title',
- description: 'workspace.upgrade.reportFields.description',
- icon: 'Pencil',
- },
- ],
-
+ get UPGRADE_FEATURE_INTRO_MAPPING() {
+ return {
+ reportFields: {
+ id: 'reportFields' as const,
+ alias: 'report-fields',
+ name: 'Report Fields',
+ title: 'workspace.upgrade.reportFields.title' as const,
+ description: 'workspace.upgrade.reportFields.description' as const,
+ icon: 'Pencil',
+ },
+ [this.POLICY.CONNECTIONS.NAME.NETSUITE]: {
+ id: this.POLICY.CONNECTIONS.NAME.NETSUITE,
+ alias: 'netsuite',
+ name: this.POLICY.CONNECTIONS.NAME_USER_FRIENDLY.netsuite,
+ title: `workspace.upgrade.${this.POLICY.CONNECTIONS.NAME.NETSUITE}.title` as const,
+ description: `workspace.upgrade.${this.POLICY.CONNECTIONS.NAME.NETSUITE}.description` as const,
+ icon: 'NetSuiteSquare',
+ },
+ [this.POLICY.CONNECTIONS.NAME.SAGE_INTACCT]: {
+ id: this.POLICY.CONNECTIONS.NAME.SAGE_INTACCT,
+ alias: 'sage-intacct',
+ name: this.POLICY.CONNECTIONS.NAME_USER_FRIENDLY.intacct,
+ title: `workspace.upgrade.${this.POLICY.CONNECTIONS.NAME.SAGE_INTACCT}.title` as const,
+ description: `workspace.upgrade.${this.POLICY.CONNECTIONS.NAME.SAGE_INTACCT}.description` as const,
+ icon: 'IntacctSquare',
+ },
+ glCodes: {
+ id: 'glCodes' as const,
+ alias: 'gl-codes',
+ name: 'GL codes',
+ title: 'workspace.upgrade.glCodes.title' as const,
+ description: 'workspace.upgrade.glCodes.description' as const,
+ icon: 'Tag',
+ },
+ glAndPayrollCodes: {
+ id: 'glAndPayrollCodes' as const,
+ alias: 'gl-and-payroll-codes',
+ name: 'GL & Payroll codes',
+ title: 'workspace.upgrade.glAndPayrollCodes.title' as const,
+ description: 'workspace.upgrade.glAndPayrollCodes.description' as const,
+ icon: 'FolderOpen',
+ },
+ };
+ },
REPORT_FIELD_TYPES: {
TEXT: 'text',
DATE: 'date',
diff --git a/src/Expensify.tsx b/src/Expensify.tsx
index f9fd379d94ce..6151f983e8d0 100644
--- a/src/Expensify.tsx
+++ b/src/Expensify.tsx
@@ -3,13 +3,12 @@ import React, {useCallback, useEffect, useLayoutEffect, useMemo, useRef, useStat
import type {NativeEventSubscription} from 'react-native';
import {AppState, Linking, NativeModules} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
-import Onyx, {useOnyx, withOnyx} from 'react-native-onyx';
+import Onyx, {withOnyx} from 'react-native-onyx';
import ConfirmModal from './components/ConfirmModal';
import DeeplinkWrapper from './components/DeeplinkWrapper';
import EmojiPicker from './components/EmojiPicker/EmojiPicker';
import FocusModeNotification from './components/FocusModeNotification';
import GrowlNotification from './components/GrowlNotification';
-import RequireTwoFactorAuthenticationModal from './components/RequireTwoFactorAuthenticationModal';
import AppleAuthWrapper from './components/SignInButtons/AppleAuthWrapper';
import SplashScreenHider from './components/SplashScreenHider';
import UpdateAppModal from './components/UpdateAppModal';
@@ -38,7 +37,6 @@ import ONYXKEYS from './ONYXKEYS';
import PopoverReportActionContextMenu from './pages/home/report/ContextMenu/PopoverReportActionContextMenu';
import * as ReportActionContextMenu from './pages/home/report/ContextMenu/ReportActionContextMenu';
import type {Route} from './ROUTES';
-import ROUTES from './ROUTES';
import type {ScreenShareRequest, Session} from './types/onyx';
Onyx.registerLogger(({level, message}) => {
@@ -103,16 +101,6 @@ function Expensify({
const [isSplashHidden, setIsSplashHidden] = useState(false);
const [hasAttemptedToOpenPublicRoom, setAttemptedToOpenPublicRoom] = useState(false);
const {translate} = useLocalize();
- const [account] = useOnyx(ONYXKEYS.ACCOUNT);
- const [shouldShowRequire2FAModal, setShouldShowRequire2FAModal] = useState(false);
-
- useEffect(() => {
- if (!account?.needsTwoFactorAuthSetup || account.requiresTwoFactorAuth) {
- return;
- }
- setShouldShowRequire2FAModal(true);
- }, [account?.needsTwoFactorAuthSetup, account?.requiresTwoFactorAuth]);
-
const [initialUrl, setInitialUrl] = useState(null);
useEffect(() => {
@@ -265,16 +253,6 @@ function Expensify({
/>
) : null}
{focusModeNotification ? : null}
- {shouldShowRequire2FAModal ? (
- {
- setShouldShowRequire2FAModal(false);
- Navigation.navigate(ROUTES.SETTINGS_2FA.getRoute(ROUTES.HOME));
- }}
- isVisible
- description={translate('twoFactorAuth.twoFactorAuthIsRequiredForAdminsDescription')}
- />
- ) : null}
>
)}
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index c71990212334..ee31b52750f4 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -134,7 +134,7 @@ const ONYXKEYS = {
NVP_LAST_PAYMENT_METHOD: 'nvp_private_lastPaymentMethod',
/** This NVP holds to most recent waypoints that a person has used when creating a distance expense */
- NVP_RECENT_WAYPOINTS: 'expensify_recentWaypoints',
+ NVP_RECENT_WAYPOINTS: 'nvp_expensify_recentWaypoints',
/** This NVP contains the choice that the user made on the engagement modal */
NVP_INTRO_SELECTED: 'nvp_introSelected',
@@ -451,6 +451,9 @@ const ONYXKEYS = {
/** The bank account that Expensify Card payments will be reconciled against */
SHARED_NVP_EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION: 'sharedNVP_expensifyCard_continuousReconciliationConnection_',
+
+ /** If continuous reconciliation is enabled */
+ SHARED_NVP_EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION: 'sharedNVP_expensifyCard_useContinuousReconciliation_',
},
/** List of Form ids */
@@ -558,6 +561,8 @@ const ONYXKEYS = {
WORKSPACE_NEW_TAX_FORM: 'workspaceNewTaxForm',
WORKSPACE_NEW_TAX_FORM_DRAFT: 'workspaceNewTaxFormDraft',
WORKSPACE_TAX_NAME_FORM: 'workspaceTaxNameForm',
+ WORKSPACE_TAX_CODE_FORM: 'workspaceTaxCodeForm',
+ WORKSPACE_TAX_CODE_FORM_DRAFT: 'workspaceTaxCodeFormDraft',
WORKSPACE_TAX_NAME_FORM_DRAFT: 'workspaceTaxNameFormDraft',
WORKSPACE_TAX_VALUE_FORM: 'workspaceTaxValueForm',
WORKSPACE_TAX_VALUE_FORM_DRAFT: 'workspaceTaxValueFormDraft',
@@ -639,6 +644,7 @@ type OnyxFormValuesMapping = {
[ONYXKEYS.FORMS.POLICY_DISTANCE_RATE_EDIT_FORM]: FormTypes.PolicyDistanceRateEditForm;
[ONYXKEYS.FORMS.POLICY_DISTANCE_RATE_TAX_RECLAIMABLE_ON_EDIT_FORM]: FormTypes.PolicyDistanceRateTaxReclaimableOnEditForm;
[ONYXKEYS.FORMS.WORKSPACE_TAX_NAME_FORM]: FormTypes.WorkspaceTaxNameForm;
+ [ONYXKEYS.FORMS.WORKSPACE_TAX_CODE_FORM]: FormTypes.WorkspaceTaxCodeForm;
[ONYXKEYS.FORMS.WORKSPACE_TAX_VALUE_FORM]: FormTypes.WorkspaceTaxValueForm;
[ONYXKEYS.FORMS.NEW_CHAT_NAME_FORM]: FormTypes.NewChatNameForm;
[ONYXKEYS.FORMS.SUBSCRIPTION_SIZE_FORM]: FormTypes.SubscriptionSizeForm;
@@ -699,6 +705,7 @@ type OnyxCollectionValuesMapping = {
[ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_EXPENSIFY_CARD_SETTINGS]: OnyxTypes.ExpensifyCardSettings;
[ONYXKEYS.COLLECTION.WORKSPACE_CARDS_LIST]: OnyxTypes.WorkspaceCardsList;
[ONYXKEYS.COLLECTION.SHARED_NVP_EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION]: OnyxTypes.BankAccount;
+ [ONYXKEYS.COLLECTION.SHARED_NVP_EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION]: boolean;
};
type OnyxValuesMapping = {
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index f13724bf4322..0ccb210c9d7a 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -49,13 +49,19 @@ const ROUTES = {
},
},
+ SEARCH_ADVANCED_FILTERS: 'search/filters',
+
+ SEARCH_ADVANCED_FILTERS_DATE: 'search/filters/date',
+
+ SEARCH_ADVANCED_FILTERS_TYPE: 'search/filters/type',
+
SEARCH_REPORT: {
- route: '/search/:query/view/:reportID',
+ route: 'search/:query/view/:reportID',
getRoute: (query: string, reportID: string) => `search/${query}/view/${reportID}` as const,
},
TRANSACTION_HOLD_REASON_RHP: {
- route: '/search/:query/hold/:transactionID',
+ route: 'search/:query/hold/:transactionID',
getRoute: (query: string, transactionID: string) => `search/${query}/hold/${transactionID}` as const,
},
@@ -198,8 +204,7 @@ const ROUTES = {
},
SETTINGS_2FA: {
route: 'settings/security/two-factor-auth',
- getRoute: (backTo?: string, forwardTo?: string) =>
- getUrlWithBackToParam(forwardTo ? `settings/security/two-factor-auth?forwardTo=${encodeURIComponent(forwardTo)}` : 'settings/security/two-factor-auth', backTo),
+ getRoute: (backTo?: string) => getUrlWithBackToParam('settings/security/two-factor-auth', backTo),
},
SETTINGS_STATUS: 'settings/profile/status',
@@ -700,7 +705,8 @@ const ROUTES = {
},
WORKSPACE_UPGRADE: {
route: 'settings/workspaces/:policyID/upgrade/:featureName',
- getRoute: (policyID: string, featureName: string) => `settings/workspaces/${policyID}/upgrade/${encodeURIComponent(featureName)}` as const,
+ getRoute: (policyID: string, featureName: string, backTo?: string) =>
+ getUrlWithBackToParam(`settings/workspaces/${policyID}/upgrade/${encodeURIComponent(featureName)}` as const, backTo),
},
WORKSPACE_CATEGORIES_SETTINGS: {
route: 'settings/workspaces/:policyID/categories/settings',
@@ -815,6 +821,10 @@ const ROUTES = {
route: 'settings/workspaces/:policyID/tax/:taxID/value',
getRoute: (policyID: string, taxID: string) => `settings/workspaces/${policyID}/tax/${encodeURIComponent(taxID)}/value` as const,
},
+ WORKSPACE_TAX_CODE: {
+ route: 'settings/workspaces/:policyID/tax/:taxID/tax-code',
+ getRoute: (policyID: string, taxID: string) => `settings/workspaces/${policyID}/tax/${encodeURIComponent(taxID)}/tax-code` as const,
+ },
WORKSPACE_REPORT_FIELDS: {
route: 'settings/workspaces/:policyID/reportFields',
getRoute: (policyID: string) => `settings/workspaces/${policyID}/reportFields` as const,
diff --git a/src/SCREENS.ts b/src/SCREENS.ts
index 3a0bb2248303..6e5814209171 100644
--- a/src/SCREENS.ts
+++ b/src/SCREENS.ts
@@ -30,6 +30,9 @@ const SCREENS = {
SEARCH: {
CENTRAL_PANE: 'Search_Central_Pane',
REPORT_RHP: 'Search_Report_RHP',
+ ADVANCED_FILTERS_RHP: 'Search_Advanced_Filters_RHP',
+ ADVANCED_FILTERS_DATE_RHP: 'Search_Advanced_Filters_Date_RHP',
+ ADVANCED_FILTERS_TYPE_RHP: 'Search_Advanced_Filters_Type_RHP',
TRANSACTION_HOLD_REASON_RHP: 'Search_Transaction_Hold_Reason_RHP',
BOTTOM_TAB: 'Search_Bottom_Tab',
},
@@ -145,6 +148,7 @@ const SCREENS = {
TRANSACTION_DUPLICATE: 'TransactionDuplicate',
TRAVEL: 'Travel',
SEARCH_REPORT: 'SearchReport',
+ SEARCH_ADVANCED_FILTERS: 'SearchAdvancedFilters',
SETTINGS_CATEGORIES: 'SettingsCategories',
RESTRICTED_ACTION: 'RestrictedAction',
REPORT_EXPORT: 'Report_Export',
@@ -371,6 +375,7 @@ const SCREENS = {
TAX_EDIT: 'Workspace_Tax_Edit',
TAX_NAME: 'Workspace_Tax_Name',
TAX_VALUE: 'Workspace_Tax_Value',
+ TAX_CODE: 'Workspace_Tax_Code',
TAXES_SETTINGS: 'Workspace_Taxes_Settings',
TAXES_SETTINGS_CUSTOM_TAX_NAME: 'Workspace_Taxes_Settings_CustomTaxName',
TAXES_SETTINGS_WORKSPACE_CURRENCY_DEFAULT: 'Workspace_Taxes_Settings_WorkspaceCurrency',
diff --git a/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/TransparentOverlay/TransparentOverlay.tsx b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/TransparentOverlay/TransparentOverlay.tsx
new file mode 100644
index 000000000000..c761faccad39
--- /dev/null
+++ b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/TransparentOverlay/TransparentOverlay.tsx
@@ -0,0 +1,47 @@
+import React, {useCallback} from 'react';
+import {View} from 'react-native';
+import type {PointerEvent} from 'react-native';
+import type PressableProps from '@components/Pressable/GenericPressable/types';
+import PressableWithoutFeedback from '@components/Pressable/PressableWithoutFeedback';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import CONST from '@src/CONST';
+
+type TransparentOverlayProps = {
+ resetSuggestions: () => void;
+};
+
+type OnPressHandler = PressableProps['onPress'];
+
+function TransparentOverlay({resetSuggestions}: TransparentOverlayProps) {
+ const {translate} = useLocalize();
+ const styles = useThemeStyles();
+
+ const onResetSuggestions = useCallback>(
+ (event) => {
+ event?.preventDefault();
+ resetSuggestions();
+ },
+ [resetSuggestions],
+ );
+
+ const handlePointerDown = useCallback((e: PointerEvent) => {
+ e?.preventDefault();
+ }, []);
+
+ return (
+
+
+
+ );
+}
+
+export default TransparentOverlay;
diff --git a/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.native.tsx b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.native.tsx
index 9848d77e479e..9ac43c4d8830 100644
--- a/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.native.tsx
+++ b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.native.tsx
@@ -4,9 +4,10 @@ import {View} from 'react-native';
import BaseAutoCompleteSuggestions from '@components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions';
import useStyleUtils from '@hooks/useStyleUtils';
import getBottomSuggestionPadding from './getBottomSuggestionPadding';
+import TransparentOverlay from './TransparentOverlay/TransparentOverlay';
import type {AutoCompleteSuggestionsPortalProps} from './types';
-function AutoCompleteSuggestionsPortal({left = 0, width = 0, bottom = 0, ...props}: AutoCompleteSuggestionsPortalProps) {
+function AutoCompleteSuggestionsPortal({left = 0, width = 0, bottom = 0, resetSuggestions = () => {}, ...props}: AutoCompleteSuggestionsPortalProps) {
const StyleUtils = useStyleUtils();
const styles = useMemo(() => StyleUtils.getBaseAutoCompleteSuggestionContainerStyle({left, width, bottom: bottom + getBottomSuggestionPadding()}), [StyleUtils, left, width, bottom]);
@@ -16,6 +17,7 @@ function AutoCompleteSuggestionsPortal({left = 0, width = 0, bottom
return (
+
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
diff --git a/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.tsx b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.tsx
index 2d1d533c2859..d26dd0422368 100644
--- a/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.tsx
+++ b/src/components/AutoCompleteSuggestions/AutoCompleteSuggestionsPortal/index.tsx
@@ -5,6 +5,7 @@ import {View} from 'react-native';
import BaseAutoCompleteSuggestions from '@components/AutoCompleteSuggestions/BaseAutoCompleteSuggestions';
import useStyleUtils from '@hooks/useStyleUtils';
import getBottomSuggestionPadding from './getBottomSuggestionPadding';
+import TransparentOverlay from './TransparentOverlay/TransparentOverlay';
import type {AutoCompleteSuggestionsPortalProps} from './types';
/**
@@ -14,7 +15,13 @@ import type {AutoCompleteSuggestionsPortalProps} from './types';
* On the native platform, tapping on auto-complete suggestions will not blur the main input.
*/
-function AutoCompleteSuggestionsPortal({left = 0, width = 0, bottom = 0, ...props}: AutoCompleteSuggestionsPortalProps): ReactElement | null | false {
+function AutoCompleteSuggestionsPortal({
+ left = 0,
+ width = 0,
+ bottom = 0,
+ resetSuggestions = () => {},
+ ...props
+}: AutoCompleteSuggestionsPortalProps): ReactElement | null | false {
const StyleUtils = useStyleUtils();
const bodyElement = document.querySelector('body');
@@ -31,7 +38,10 @@ function AutoCompleteSuggestionsPortal({left = 0, width = 0, bottom
!!width &&
bodyElement &&
ReactDOM.createPortal(
- {componentToRender},
+ <>
+
+ {componentToRender}
+ >,
bodyElement,
)
);
diff --git a/src/components/AutoCompleteSuggestions/index.tsx b/src/components/AutoCompleteSuggestions/index.tsx
index 1aa486eccd4d..41a01fa27c46 100644
--- a/src/components/AutoCompleteSuggestions/index.tsx
+++ b/src/components/AutoCompleteSuggestions/index.tsx
@@ -34,6 +34,13 @@ function isEnoughSpaceToRenderMenuAboveCursor({y, cursorCoordinates, scrollValue
return y + (cursorCoordinates.y - scrollValue) > contentHeight + topInset + CONST.AUTO_COMPLETE_SUGGESTER.SUGGESTION_BOX_MAX_SAFE_DISTANCE;
}
+const initialContainerState = {
+ width: 0,
+ left: 0,
+ bottom: 0,
+ cursorCoordinates: {x: 0, y: 0},
+};
+
/**
* On the mobile-web platform, when long-pressing on auto-complete suggestions,
* we need to prevent focus shifting to avoid blurring the main input (which makes the suggestions picker close and fires the onSelect callback).
@@ -48,12 +55,7 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu
const prevLeftValue = React.useRef(0);
const {windowHeight, windowWidth, isSmallScreenWidth} = useWindowDimensions();
const [suggestionHeight, setSuggestionHeight] = React.useState(0);
- const [containerState, setContainerState] = React.useState({
- width: 0,
- left: 0,
- bottom: 0,
- cursorCoordinates: {x: 0, y: 0},
- });
+ const [containerState, setContainerState] = React.useState(initialContainerState);
const StyleUtils = useStyleUtils();
const insets = useSafeAreaInsets();
const {keyboardHeight} = useKeyboardState();
@@ -80,6 +82,11 @@ function AutoCompleteSuggestions({measureParentContainerAndReportCu
return;
}
+ if (!windowHeight || !windowWidth || !suggestionsLength) {
+ setContainerState(initialContainerState);
+ return;
+ }
+
measureParentContainerAndReportCursor(({x, y, width, scrollValue, cursorCoordinates}: MeasureParentContainerAndCursor) => {
const xCoordinatesOfCursor = x + cursorCoordinates.x;
const bigScreenLeftOffset =
diff --git a/src/components/AutoCompleteSuggestions/types.ts b/src/components/AutoCompleteSuggestions/types.ts
index 48bb6b713032..57347cd65abe 100644
--- a/src/components/AutoCompleteSuggestions/types.ts
+++ b/src/components/AutoCompleteSuggestions/types.ts
@@ -42,6 +42,9 @@ type AutoCompleteSuggestionsProps = {
/** Measures the parent container's position and dimensions. Also add a cursor coordinates */
measureParentContainerAndReportCursor?: (props: MeasureParentContainerAndCursorCallback) => void;
+
+ /** Reset the emoji suggestions */
+ resetSuggestions?: () => void;
};
export type {AutoCompleteSuggestionsProps, RenderSuggestionMenuItemProps, MeasureParentContainerAndCursorCallback, MeasureParentContainerAndCursor};
diff --git a/src/components/Checkbox.tsx b/src/components/Checkbox.tsx
index 5445816f067b..6da170da3a67 100644
--- a/src/components/Checkbox.tsx
+++ b/src/components/Checkbox.tsx
@@ -44,6 +44,9 @@ type CheckboxProps = Partial & {
/** An accessibility label for the checkbox */
accessibilityLabel: string;
+
+ /** stop propagation of the mouse down event */
+ shouldStopMouseDownPropagation?: boolean;
};
function Checkbox(
@@ -60,6 +63,7 @@ function Checkbox(
caretSize = 14,
onPress,
accessibilityLabel,
+ shouldStopMouseDownPropagation,
}: CheckboxProps,
ref: ForwardedRef,
) {
@@ -89,7 +93,12 @@ function Checkbox(
{
+ if (shouldStopMouseDownPropagation) {
+ e.stopPropagation();
+ }
+ onMouseDown?.(e);
+ }}
ref={ref}
style={[StyleUtils.getCheckboxPressableStyle(containerBorderRadius + 2), style]} // to align outline on focus, border-radius of pressable should be 2px more than Checkbox
onKeyDown={handleSpaceKey}
diff --git a/src/components/ConnectToNetSuiteButton/index.tsx b/src/components/ConnectToNetSuiteButton/index.tsx
index b741d584a49e..928bc01f12c1 100644
--- a/src/components/ConnectToNetSuiteButton/index.tsx
+++ b/src/components/ConnectToNetSuiteButton/index.tsx
@@ -1,5 +1,6 @@
import React, {useRef, useState} from 'react';
import type {View} from 'react-native';
+import {useOnyx} from 'react-native-onyx';
import AccountingConnectionConfirmationModal from '@components/AccountingConnectionConfirmationModal';
import Button from '@components/Button';
import * as Expensicons from '@components/Icon/Expensicons';
@@ -11,8 +12,10 @@ import useWindowDimensions from '@hooks/useWindowDimensions';
import {removePolicyConnection} from '@libs/actions/connections';
import {getAdminPoliciesConnectedToNetSuite} from '@libs/actions/Policy/Policy';
import Navigation from '@libs/Navigation/Navigation';
+import {isControlPolicy} from '@libs/PolicyUtils';
import type {AnchorPosition} from '@styles/index';
import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
import ROUTES from '@src/ROUTES';
import type {ConnectToNetSuiteButtonProps} from './types';
@@ -20,6 +23,7 @@ function ConnectToNetSuiteButton({policyID, shouldDisconnectIntegrationBeforeCon
const styles = useThemeStyles();
const {translate} = useLocalize();
const {isOffline} = useNetwork();
+ const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
const [isDisconnectModalOpen, setIsDisconnectModalOpen] = useState(false);
@@ -51,6 +55,11 @@ function ConnectToNetSuiteButton({policyID, shouldDisconnectIntegrationBeforeCon
<>
diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar/index.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
similarity index 72%
rename from src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar/index.tsx
rename to src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
index f244342c28ae..1ee25b45d331 100644
--- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar/index.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar.tsx
@@ -1,8 +1,7 @@
-import {useNavigation, useNavigationState} from '@react-navigation/native';
+import {useNavigation} from '@react-navigation/native';
import React, {memo, useCallback, useEffect} from 'react';
import {NativeModules, View} from 'react-native';
-import type {OnyxEntry} from 'react-native-onyx';
-import {withOnyx} from 'react-native-onyx';
+import {useOnyx} from 'react-native-onyx';
import Icon from '@components/Icon';
import * as Expensicons from '@components/Icon/Expensicons';
import {PressableWithFeedback} from '@components/Pressable';
@@ -13,8 +12,6 @@ import useTheme from '@hooks/useTheme';
import useThemeStyles from '@hooks/useThemeStyles';
import * as Session from '@libs/actions/Session';
import interceptAnonymousUser from '@libs/interceptAnonymousUser';
-import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute';
-import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
import Navigation from '@libs/Navigation/Navigation';
import type {RootStackParamList, State} from '@libs/Navigation/types';
import {isCentralPaneName} from '@libs/NavigationUtils';
@@ -30,17 +27,17 @@ import type {Route} from '@src/ROUTES';
import ROUTES from '@src/ROUTES';
import SCREENS from '@src/SCREENS';
-type PurposeForUsingExpensifyModalOnyxProps = {
- isLoadingApp: OnyxEntry;
+type BottomTabBarProps = {
+ selectedTab: string | undefined;
};
-type PurposeForUsingExpensifyModalProps = PurposeForUsingExpensifyModalOnyxProps;
-function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps) {
+function BottomTabBar({selectedTab}: BottomTabBarProps) {
const theme = useTheme();
const styles = useThemeStyles();
const {translate} = useLocalize();
const navigation = useNavigation();
const {activeWorkspaceID} = useActiveWorkspace();
+ const [isLoadingApp] = useOnyx(ONYXKEYS.IS_LOADING_APP);
useEffect(() => {
const navigationState = navigation.getState() as State | undefined;
@@ -61,27 +58,14 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
// eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
}, [isLoadingApp]);
- // Parent navigator of the bottom tab bar is the root navigator.
- const currentTabName = useNavigationState((state) => {
- const topmostCentralPaneRoute = getTopmostCentralPaneRoute(state);
-
- if (topmostCentralPaneRoute && topmostCentralPaneRoute.name === SCREENS.SEARCH.CENTRAL_PANE) {
- return SCREENS.SEARCH.CENTRAL_PANE;
- }
-
- const topmostBottomTabRoute = getTopmostBottomTabRoute(state);
- return topmostBottomTabRoute?.name ?? SCREENS.HOME;
- });
-
const chatTabBrickRoad = getChatTabBrickRoad(activeWorkspaceID);
-
const navigateToChats = useCallback(() => {
- if (currentTabName === SCREENS.HOME) {
+ if (selectedTab === SCREENS.HOME) {
return;
}
- const route = activeWorkspaceID ? (`/w/${activeWorkspaceID}/home` as Route) : ROUTES.HOME;
+ const route = activeWorkspaceID ? (`/w/${activeWorkspaceID}/${ROUTES.HOME}` as Route) : ROUTES.HOME;
Navigation.navigate(route);
- }, [activeWorkspaceID, currentTabName]);
+ }, [activeWorkspaceID, selectedTab]);
return (
@@ -96,7 +80,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
@@ -109,7 +93,7 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
{
- if (currentTabName === SCREENS.SEARCH.BOTTOM_TAB || currentTabName === SCREENS.SEARCH.CENTRAL_PANE) {
+ if (selectedTab === SCREENS.SEARCH.BOTTOM_TAB) {
return;
}
interceptAnonymousUser(() => Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.SEARCH.TAB.ALL)));
@@ -122,14 +106,14 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
-
+
@@ -139,8 +123,4 @@ function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps
BottomTabBar.displayName = 'BottomTabBar';
-export default withOnyx({
- isLoadingApp: {
- key: ONYXKEYS.IS_LOADING_APP,
- },
-})(memo(BottomTabBar));
+export default memo(BottomTabBar);
diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar/index.website.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar/index.website.tsx
deleted file mode 100644
index 556365b473c3..000000000000
--- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/BottomTabBar/index.website.tsx
+++ /dev/null
@@ -1,146 +0,0 @@
-import {useNavigation, useNavigationState} from '@react-navigation/native';
-import React, {useCallback, useEffect} from 'react';
-import {View} from 'react-native';
-import type {OnyxEntry} from 'react-native-onyx';
-import {withOnyx} from 'react-native-onyx';
-import type {TupleToUnion} from 'type-fest';
-import Icon from '@components/Icon';
-import * as Expensicons from '@components/Icon/Expensicons';
-import {PressableWithFeedback} from '@components/Pressable';
-import Tooltip from '@components/Tooltip';
-import useActiveBottomTabRoute from '@hooks/useActiveBottomTabRoute';
-import useActiveWorkspace from '@hooks/useActiveWorkspace';
-import useLocalize from '@hooks/useLocalize';
-import useTheme from '@hooks/useTheme';
-import useThemeStyles from '@hooks/useThemeStyles';
-import * as Session from '@libs/actions/Session';
-import interceptAnonymousUser from '@libs/interceptAnonymousUser';
-import getTopmostBottomTabRoute from '@libs/Navigation/getTopmostBottomTabRoute';
-import getTopmostCentralPaneRoute from '@libs/Navigation/getTopmostCentralPaneRoute';
-import Navigation from '@libs/Navigation/Navigation';
-import type {RootStackParamList, State} from '@libs/Navigation/types';
-import {isCentralPaneName, isHomeTabName, isSearchTabName, isSettingTabName} from '@libs/NavigationUtils';
-import {getChatTabBrickRoad} from '@libs/WorkspacesSettingsUtils';
-import BottomTabAvatar from '@pages/home/sidebar/BottomTabAvatar';
-import BottomTabBarFloatingActionButton from '@pages/home/sidebar/BottomTabBarFloatingActionButton';
-import variables from '@styles/variables';
-import * as Welcome from '@userActions/Welcome';
-import CONST from '@src/CONST';
-import NAVIGATORS from '@src/NAVIGATORS';
-import ONYXKEYS from '@src/ONYXKEYS';
-import type {Route} from '@src/ROUTES';
-import ROUTES from '@src/ROUTES';
-import SCREENS from '@src/SCREENS';
-
-type PurposeForUsingExpensifyModalOnyxProps = {
- isLoadingApp: OnyxEntry;
-};
-type PurposeForUsingExpensifyModalProps = PurposeForUsingExpensifyModalOnyxProps;
-
-function BottomTabBar({isLoadingApp = false}: PurposeForUsingExpensifyModalProps) {
- const theme = useTheme();
- const styles = useThemeStyles();
- const {translate} = useLocalize();
- const navigation = useNavigation();
- const HOME_SCREENS = [SCREENS.HOME, SCREENS.REPORT];
- const {activeWorkspaceID: contextActiveWorkspaceID} = useActiveWorkspace();
- const activeWorkspaceID = sessionStorage.getItem(CONST.SESSION_STORAGE_KEYS.ACTIVE_WORKSPACE_ID) ?? contextActiveWorkspaceID;
-
- useEffect(() => {
- const navigationState = navigation.getState() as State | undefined;
- const routes = navigationState?.routes;
- const currentRoute = routes?.[navigationState?.index ?? 0];
- // When we are redirected to the Settings tab from the OldDot, we don't want to call the Welcome.show() method.
- // To prevent this, the value of the bottomTabRoute?.name is checked here
- if (!!(currentRoute && currentRoute.name !== NAVIGATORS.BOTTOM_TAB_NAVIGATOR && !isCentralPaneName(currentRoute.name)) || Session.isAnonymousUser()) {
- return;
- }
-
- Welcome.isOnboardingFlowCompleted({onNotCompleted: () => Navigation.navigate(ROUTES.ONBOARDING_ROOT)});
- // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
- }, [isLoadingApp]);
-
- // Parent navigator of the bottom tab bar is the root navigator.
- const currentTabName = useNavigationState((state) => {
- const topmostCentralPaneRoute = getTopmostCentralPaneRoute(state);
-
- if (topmostCentralPaneRoute && topmostCentralPaneRoute.name === SCREENS.SEARCH.CENTRAL_PANE) {
- return SCREENS.SEARCH.CENTRAL_PANE;
- }
-
- const topmostBottomTabRoute = getTopmostBottomTabRoute(state);
- return topmostBottomTabRoute?.name ?? SCREENS.HOME;
- });
-
- const activeBottomTabRoute = useActiveBottomTabRoute();
- const chatTabBrickRoad = getChatTabBrickRoad(activeWorkspaceID);
-
- const navigateToChats = useCallback(() => {
- if (currentTabName === SCREENS.HOME) {
- return;
- }
- const route = activeWorkspaceID ? (`/w/${activeWorkspaceID}/home` as Route) : ROUTES.HOME;
- Navigation.navigate(route);
- }, [activeWorkspaceID, currentTabName]);
-
- return (
-
-
-
-
- ) ? theme.iconMenu : theme.icon}
- width={variables.iconBottomBar}
- height={variables.iconBottomBar}
- />
- {chatTabBrickRoad && (
-
- )}
-
-
-
-
- {
- if (isSearchTabName(activeBottomTabRoute?.name)) {
- return;
- }
- interceptAnonymousUser(() => Navigation.navigate(ROUTES.SEARCH.getRoute(CONST.SEARCH.TAB.ALL)));
- }}
- role={CONST.ROLE.BUTTON}
- accessibilityLabel={translate('common.search')}
- wrapperStyle={styles.flex1}
- style={styles.bottomTabBarItem}
- >
-
-
-
-
-
-
-
-
-
-
- );
-}
-
-BottomTabBar.displayName = 'BottomTabBar';
-
-export default withOnyx({
- isLoadingApp: {
- key: ONYXKEYS.IS_LOADING_APP,
- },
-})(BottomTabBar);
diff --git a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx
index 6a6f44df20bd..89b83dae816c 100644
--- a/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx
+++ b/src/libs/Navigation/AppNavigator/createCustomBottomTabNavigator/index.tsx
@@ -44,6 +44,7 @@ function CustomBottomTabNavigator({initialRouteName, children, screenOptions, ..
const styles = useThemeStyles();
const stateToRender = getStateToRender(state);
+ const selectedTab = stateToRender.routes.at(-1)?.name;
return (
-
+
);
diff --git a/src/libs/Navigation/Navigation.ts b/src/libs/Navigation/Navigation.ts
index 6f803ae1e497..10301e0a99b3 100644
--- a/src/libs/Navigation/Navigation.ts
+++ b/src/libs/Navigation/Navigation.ts
@@ -144,10 +144,6 @@ function getActiveRoute(): string {
return '';
}
- if (currentRoute?.path) {
- return currentRoute.path;
- }
-
const routeFromState = getPathFromState(navigationRef.getRootState(), linkingConfig.config);
if (routeFromState) {
diff --git a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts
index 83929b7e7d02..c6f3aa2f17b5 100755
--- a/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts
+++ b/src/libs/Navigation/linkingConfig/CENTRAL_PANE_TO_RHP_MAPPING.ts
@@ -38,7 +38,7 @@ const CENTRAL_PANE_TO_RHP_MAPPING: Partial> =
[SCREENS.SETTINGS.ABOUT]: [SCREENS.SETTINGS.APP_DOWNLOAD_LINKS],
[SCREENS.SETTINGS.SAVE_THE_WORLD]: [SCREENS.I_KNOW_A_TEACHER, SCREENS.INTRO_SCHOOL_PRINCIPAL, SCREENS.I_AM_A_TEACHER],
[SCREENS.SETTINGS.TROUBLESHOOT]: [SCREENS.SETTINGS.CONSOLE],
- [SCREENS.SEARCH.CENTRAL_PANE]: [SCREENS.SEARCH.REPORT_RHP, SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP],
+ [SCREENS.SEARCH.CENTRAL_PANE]: [SCREENS.SEARCH.REPORT_RHP, SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP, SCREENS.SEARCH.ADVANCED_FILTERS_RHP],
[SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: [
SCREENS.SETTINGS.SUBSCRIPTION.ADD_PAYMENT_CARD,
SCREENS.SETTINGS.SUBSCRIPTION.SIZE,
diff --git a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts
index 9bb6e817f0d8..fdecf83c6c9d 100755
--- a/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts
+++ b/src/libs/Navigation/linkingConfig/FULL_SCREEN_TO_RHP_MAPPING.ts
@@ -2,14 +2,7 @@ import type {FullScreenName} from '@libs/Navigation/types';
import SCREENS from '@src/SCREENS';
const FULL_SCREEN_TO_RHP_MAPPING: Partial> = {
- [SCREENS.WORKSPACE.PROFILE]: [
- SCREENS.WORKSPACE.NAME,
- SCREENS.WORKSPACE.ADDRESS,
- SCREENS.WORKSPACE.CURRENCY,
- SCREENS.WORKSPACE.DESCRIPTION,
- SCREENS.WORKSPACE.SHARE,
- SCREENS.WORKSPACE.UPGRADE,
- ],
+ [SCREENS.WORKSPACE.PROFILE]: [SCREENS.WORKSPACE.NAME, SCREENS.WORKSPACE.ADDRESS, SCREENS.WORKSPACE.CURRENCY, SCREENS.WORKSPACE.DESCRIPTION, SCREENS.WORKSPACE.SHARE],
[SCREENS.WORKSPACE.REIMBURSE]: [SCREENS.WORKSPACE.RATE_AND_UNIT, SCREENS.WORKSPACE.RATE_AND_UNIT_RATE, SCREENS.WORKSPACE.RATE_AND_UNIT_UNIT],
[SCREENS.WORKSPACE.MEMBERS]: [
SCREENS.WORKSPACE.INVITE,
@@ -127,6 +120,7 @@ const FULL_SCREEN_TO_RHP_MAPPING: Partial> = {
SCREENS.WORKSPACE.TAX_EDIT,
SCREENS.WORKSPACE.TAX_NAME,
SCREENS.WORKSPACE.TAX_VALUE,
+ SCREENS.WORKSPACE.TAX_CODE,
],
[SCREENS.WORKSPACE.TAGS]: [
SCREENS.WORKSPACE.TAGS_SETTINGS,
diff --git a/src/libs/Navigation/linkingConfig/config.ts b/src/libs/Navigation/linkingConfig/config.ts
index beed9f1cca92..c37536dc5419 100644
--- a/src/libs/Navigation/linkingConfig/config.ts
+++ b/src/libs/Navigation/linkingConfig/config.ts
@@ -678,6 +678,12 @@ const config: LinkingOptions['config'] = {
taxID: (taxID: string) => decodeURIComponent(taxID),
},
},
+ [SCREENS.WORKSPACE.TAX_CODE]: {
+ path: ROUTES.WORKSPACE_TAX_CODE.route,
+ parse: {
+ taxID: (taxID: string) => decodeURIComponent(taxID),
+ },
+ },
[SCREENS.WORKSPACE.TAX_NAME]: {
path: ROUTES.WORKSPACE_TAX_NAME.route,
parse: {
@@ -962,6 +968,13 @@ const config: LinkingOptions['config'] = {
[SCREENS.SEARCH.TRANSACTION_HOLD_REASON_RHP]: ROUTES.TRANSACTION_HOLD_REASON_RHP.route,
},
},
+ [SCREENS.RIGHT_MODAL.SEARCH_ADVANCED_FILTERS]: {
+ screens: {
+ [SCREENS.SEARCH.ADVANCED_FILTERS_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS,
+ [SCREENS.SEARCH.ADVANCED_FILTERS_DATE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_DATE,
+ [SCREENS.SEARCH.ADVANCED_FILTERS_TYPE_RHP]: ROUTES.SEARCH_ADVANCED_FILTERS_TYPE,
+ },
+ },
[SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: {
screens: {
[SCREENS.RESTRICTED_ACTION_ROOT]: ROUTES.RESTRICTED_ACTION.route,
diff --git a/src/libs/Navigation/types.ts b/src/libs/Navigation/types.ts
index c273b2db6a10..24af6e52b9f5 100644
--- a/src/libs/Navigation/types.ts
+++ b/src/libs/Navigation/types.ts
@@ -50,6 +50,10 @@ type NavigationPartialRoute = PartialRoute = NavigationState | PartialState>;
+type BackToParams = {
+ backTo?: Routes;
+};
+
type CentralPaneScreensParamList = {
[SCREENS.REPORT]: {
reportActionID: string;
@@ -75,15 +79,6 @@ type CentralPaneScreensParamList = {
[SCREENS.SETTINGS.SUBSCRIPTION.ROOT]: undefined;
};
-type BackToParams = {
- backTo?: Routes;
-};
-
-type BackToAndForwardToParms = {
- backTo?: Routes;
- forwardTo?: Routes;
-};
-
type SearchNavigatorParamList = {
[SCREENS.SEARCH.BOTTOM_TAB]: undefined;
[SCREENS.SEARCH.CENTRAL_PANE]: undefined;
@@ -629,10 +624,7 @@ type SettingsNavigatorParamList = {
[SCREENS.GET_ASSISTANCE]: {
backTo: Routes;
};
- [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: {
- backTo?: Routes;
- forwardTo?: string;
- };
+ [SCREENS.SETTINGS.TWO_FACTOR_AUTH]: BackToParams;
[SCREENS.SETTINGS.REPORT_CARD_LOST_OR_DAMAGED]: {
/** cardID of selected card */
cardID: string;
@@ -661,6 +653,10 @@ type SettingsNavigatorParamList = {
policyID: string;
taxID: string;
};
+ [SCREENS.WORKSPACE.TAX_CODE]: {
+ policyID: string;
+ taxID: string;
+ };
[SCREENS.WORKSPACE.EXPENSIFY_CARD_ISSUE_NEW]: {
policyID: string;
};
@@ -1059,11 +1055,11 @@ type RightModalNavigatorParamList = {
[SCREENS.RIGHT_MODAL.TRAVEL]: NavigatorScreenParams;
[SCREENS.RIGHT_MODAL.SEARCH_REPORT]: NavigatorScreenParams;
[SCREENS.RIGHT_MODAL.RESTRICTED_ACTION]: NavigatorScreenParams;
+ [SCREENS.RIGHT_MODAL.SEARCH_ADVANCED_FILTERS]: NavigatorScreenParams;
};
type TravelNavigatorParamList = {
[SCREENS.TRAVEL.MY_TRIPS]: undefined;
- [SCREENS.RIGHT_MODAL.SEARCH_REPORT]: NavigatorScreenParams;
};
type FullScreenNavigatorParamList = {
@@ -1160,8 +1156,6 @@ type ExplanationModalNavigatorParamList = {
[SCREENS.EXPLANATION_MODAL.ROOT]: undefined;
};
-type BottomTabScreensParamList = {[SCREENS.HOME]: undefined; [SCREENS.REPORT]: undefined} & SearchNavigatorParamList & SettingsNavigatorParamList;
-
type BottomTabNavigatorParamList = {
[SCREENS.HOME]: {policyID?: string};
[SCREENS.SEARCH.BOTTOM_TAB]: {
@@ -1250,6 +1244,10 @@ type SearchReportParamList = {
};
};
+type SearchAdvancedFiltersParamList = {
+ [SCREENS.SEARCH.ADVANCED_FILTERS_RHP]: Record;
+};
+
type RestrictedActionParamList = {
[SCREENS.RESTRICTED_ACTION_ROOT]: {
policyID: string;
@@ -1260,8 +1258,6 @@ type RootStackParamList = PublicScreensParamList & AuthScreensParamList & LeftMo
type BottomTabName = keyof BottomTabNavigatorParamList;
-type BottomTabScreenName = keyof BottomTabScreensParamList;
-
type FullScreenName = keyof FullScreenNavigatorParamList;
type CentralPaneName = keyof CentralPaneScreensParamList;
@@ -1278,10 +1274,7 @@ export type {
CentralPaneScreensParamList,
CentralPaneName,
BackToParams,
- BackToAndForwardToParms,
BottomTabName,
- BottomTabScreenName,
- BottomTabScreensParamList,
BottomTabNavigatorParamList,
DetailsNavigatorParamList,
EditRequestNavigatorParamList,
@@ -1328,5 +1321,6 @@ export type {
WelcomeVideoModalNavigatorParamList,
TransactionDuplicateNavigatorParamList,
SearchReportParamList,
+ SearchAdvancedFiltersParamList,
RestrictedActionParamList,
};
diff --git a/src/libs/NavigationUtils.ts b/src/libs/NavigationUtils.ts
index 34e9df954688..572310e8218b 100644
--- a/src/libs/NavigationUtils.ts
+++ b/src/libs/NavigationUtils.ts
@@ -1,6 +1,4 @@
import cloneDeep from 'lodash/cloneDeep';
-import type {TupleToUnion} from 'type-fest';
-import {flattenObject} from '@src/languages/translations';
import SCREENS from '@src/SCREENS';
import getTopmostBottomTabRoute from './Navigation/getTopmostBottomTabRoute';
import type {CentralPaneName, RootStackParamList, State} from './Navigation/types';
@@ -19,14 +17,6 @@ const CENTRAL_PANE_SCREEN_NAMES = new Set([
SCREENS.REPORT,
]);
-function isCentralPaneName(screen: string | undefined): screen is CentralPaneName {
- if (!screen) {
- return false;
- }
-
- return CENTRAL_PANE_SCREEN_NAMES.has(screen as CentralPaneName);
-}
-
const removePolicyIDParamFromState = (state: State) => {
const stateCopy = cloneDeep(state);
const bottomTabRoute = getTopmostBottomTabRoute(stateCopy);
@@ -36,43 +26,11 @@ const removePolicyIDParamFromState = (state: State) => {
return stateCopy;
};
-const SETTINGS_SCREENS = Object.values(flattenObject(SCREENS.SETTINGS));
-const SEARCH_SCREENS = Object.values(flattenObject(SCREENS.SEARCH));
-const HOME_SCREENS = [SCREENS.HOME, SCREENS.REPORT];
-const BOTTOM_TAB_SCREEN_NAMES = new Set([...SETTINGS_SCREENS, ...SEARCH_SCREENS, ...HOME_SCREENS]);
-
-const SETTINGS_TAB_SCREEN_NAMES = new Set(SETTINGS_SCREENS);
-
-const SEARCH_TAB_SCREEN_NAMES = new Set(SEARCH_SCREENS);
-
-const HOME_SCREEN_NAMES = new Set(HOME_SCREENS);
-
-function isBottomTabName(screen: TupleToUnion | undefined) {
- if (!screen) {
- return false;
- }
- return BOTTOM_TAB_SCREEN_NAMES.has(screen);
-}
-
-function isSettingTabName(screen: TupleToUnion | undefined) {
- if (!screen) {
- return false;
- }
- return SETTINGS_TAB_SCREEN_NAMES.has(screen);
-}
-
-function isSearchTabName(screen: TupleToUnion | undefined) {
- if (!screen) {
- return false;
- }
- return SEARCH_TAB_SCREEN_NAMES.has(screen);
-}
-
-function isHomeTabName(screen: TupleToUnion | undefined) {
+function isCentralPaneName(screen: string | undefined): screen is CentralPaneName {
if (!screen) {
return false;
}
- return HOME_SCREEN_NAMES.has(screen);
+ return CENTRAL_PANE_SCREEN_NAMES.has(screen as CentralPaneName);
}
-export {isCentralPaneName, isBottomTabName, isSearchTabName, isSettingTabName, isHomeTabName, removePolicyIDParamFromState};
+export {isCentralPaneName, removePolicyIDParamFromState};
diff --git a/src/libs/NextStepUtils.ts b/src/libs/NextStepUtils.ts
index 0ac2878b6857..59f46b429698 100644
--- a/src/libs/NextStepUtils.ts
+++ b/src/libs/NextStepUtils.ts
@@ -79,7 +79,8 @@ function buildNextStep(report: OnyxEntry, predictedNextStatus: ValueOf & {preferChatroomsOverThreads?: boolean};
+> & {preferChatroomsOverThreads?: boolean; includeChatRoomsByParticipants?: boolean};
type HasText = {
text?: string;
@@ -2473,7 +2473,15 @@ function getFirstKeyForList(data?: Option[] | null) {
* Filters options based on the search input value
*/
function filterOptions(options: Options, searchInputValue: string, config?: FilterOptionsConfig): Options {
- const {sortByReportTypeInSearch = false, canInviteUser = true, betas = [], maxRecentReportsToShow = 0, excludeLogins = [], preferChatroomsOverThreads = false} = config ?? {};
+ const {
+ sortByReportTypeInSearch = false,
+ canInviteUser = true,
+ betas = [],
+ maxRecentReportsToShow = 0,
+ excludeLogins = [],
+ preferChatroomsOverThreads = false,
+ includeChatRoomsByParticipants = false,
+ } = config ?? {};
if (searchInputValue.trim() === '' && maxRecentReportsToShow > 0) {
return {...options, recentReports: options.recentReports.slice(0, maxRecentReportsToShow)};
}
@@ -2533,6 +2541,10 @@ function filterOptions(options: Options, searchInputValue: string, config?: Filt
if (item.subtitle) {
values.push(item.subtitle);
}
+
+ if (includeChatRoomsByParticipants) {
+ values = values.concat(getParticipantsLoginsArray(item));
+ }
}
if (!item.isChatRoom) {
diff --git a/src/libs/PolicyUtils.ts b/src/libs/PolicyUtils.ts
index bfce8a91e71a..fe53a7bcd5ce 100644
--- a/src/libs/PolicyUtils.ts
+++ b/src/libs/PolicyUtils.ts
@@ -340,6 +340,29 @@ function isInstantSubmitEnabled(policy: OnyxInputOrEntry): boolean {
return policy?.type === CONST.POLICY.TYPE.FREE || (policy?.autoReporting === true && policy?.autoReportingFrequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.INSTANT);
}
+/**
+ * This gets a "corrected" value for autoReportingFrequency. The purpose of this function is to encapsulate some logic around the "immediate" frequency.
+ *
+ * - "immediate" is actually not immediate. For that you want "instant".
+ * - (immediate && harvesting.enabled) === daily
+ * - (immediate && !harvesting.enabled) === manual
+ *
+ * Note that "daily" and "manual" only exist as options for the API, not in the database or Onyx.
+ */
+function getCorrectedAutoReportingFrequency(policy: OnyxInputOrEntry): ValueOf | undefined {
+ if (policy?.autoReportingFrequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE) {
+ return policy?.autoReportingFrequency;
+ }
+
+ if (policy?.harvesting?.enabled) {
+ // This is actually not really "immediate". It's "daily". Surprise!
+ return CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE;
+ }
+
+ // "manual" is really just "immediate" (aka "daily") with harvesting disabled
+ return CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL;
+}
+
/**
* Checks if policy's approval mode is "optional", a.k.a. "Submit & Close"
*/
@@ -793,6 +816,7 @@ export {
isDeletedPolicyEmployee,
isFreeGroupPolicy,
isInstantSubmitEnabled,
+ getCorrectedAutoReportingFrequency,
isPaidGroupPolicy,
isPendingDeletePolicy,
isPolicyAdmin,
diff --git a/src/libs/ReportActionsUtils.ts b/src/libs/ReportActionsUtils.ts
index 1aaa5cd7bfee..e95935da3669 100644
--- a/src/libs/ReportActionsUtils.ts
+++ b/src/libs/ReportActionsUtils.ts
@@ -1,7 +1,7 @@
import {fastMerge} from 'expensify-common';
import _ from 'lodash';
import lodashFindLast from 'lodash/findLast';
-import type {OnyxCollection, OnyxCollectionInputValue, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
+import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import CONST from '@src/CONST';
@@ -10,8 +10,8 @@ import ONYXKEYS from '@src/ONYXKEYS';
import type {OnyxInputOrEntry} from '@src/types/onyx';
import type {JoinWorkspaceResolution, OriginalMessageExportIntegration} from '@src/types/onyx/OriginalMessage';
import type Report from '@src/types/onyx/Report';
-import type {Message, OldDotReportAction, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction';
import type ReportAction from '@src/types/onyx/ReportAction';
+import type {Message, OldDotReportAction, OriginalMessage, ReportActions} from '@src/types/onyx/ReportAction';
import type ReportActionName from '@src/types/onyx/ReportActionName';
import {isEmptyObject} from '@src/types/utils/EmptyObject';
import DateUtils from './DateUtils';
@@ -715,10 +715,12 @@ function replaceBaseURLInPolicyChangeLogAction(reportAction: ReportAction): Repo
return updatedReportAction;
}
-function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection | OnyxCollectionInputValue = {}): OnyxEntry {
+function getLastVisibleAction(reportID: string, actionsToMerge: Record | null> = {}): OnyxEntry {
let reportActions: Array = [];
if (!_.isEmpty(actionsToMerge)) {
- reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true));
+ reportActions = Object.values(fastMerge(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {}, actionsToMerge ?? {}, true)) as Array<
+ ReportAction | null | undefined
+ >;
} else {
reportActions = Object.values(allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${reportID}`] ?? {});
}
@@ -732,7 +734,7 @@ function getLastVisibleAction(reportID: string, actionsToMerge: OnyxCollection | OnyxCollectionInputValue = {},
+ actionsToMerge: Record | null> = {},
reportAction: OnyxInputOrEntry | undefined = undefined,
): LastVisibleMessage {
const lastVisibleAction = reportAction ?? getLastVisibleAction(reportID, actionsToMerge);
@@ -752,7 +754,7 @@ function getLastVisibleMessage(
};
}
- let messageText = getTextFromHtml(message?.html) ?? '';
+ let messageText = getReportActionMessageText(lastVisibleAction) ?? '';
if (messageText) {
messageText = StringUtils.lineBreaksToSpaces(String(messageText)).substring(0, CONST.REPORT.LAST_MESSAGE_TEXT_MAX_LENGTH).trim();
}
@@ -1534,92 +1536,92 @@ function getExportIntegrationActionFragments(reportAction: OnyxEntry;
type OptimisticIOUReportAction = Pick<
@@ -1286,12 +1288,9 @@ function isClosedExpenseReportWithNoExpenses(report: OnyxEntry): boolean
/**
* Whether the provided report is an archived room
*/
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
function isArchivedRoom(report: OnyxInputOrEntry, reportNameValuePairs?: OnyxInputOrEntry): boolean {
- if (reportNameValuePairs) {
- return reportNameValuePairs.private_isArchived;
- }
-
- return report?.statusNum === CONST.REPORT.STATUS_NUM.CLOSED && report?.stateNum === CONST.REPORT.STATE_NUM.APPROVED;
+ return !!report?.private_isArchived;
}
/**
@@ -1730,7 +1729,7 @@ function formatReportLastMessageText(lastMessageText: string, isModifiedExpenseM
/**
* Helper method to return the default avatar associated with the given login
*/
-function getDefaultWorkspaceAvatar(workspaceName?: string): IconAsset {
+function getDefaultWorkspaceAvatar(workspaceName?: string): React.FC {
if (!workspaceName) {
return defaultWorkspaceAvatars.WorkspaceBuilding;
}
@@ -4117,7 +4116,6 @@ function buildOptimisticIOUReportAction(
iouReportID = '',
isSettlingUp = false,
isSendMoneyFlow = false,
- receipt: Receipt = {},
isOwnPolicyExpenseChat = false,
created = DateUtils.getDBTime(),
linkedExpenseReportAction?: OnyxEntry,
@@ -4131,7 +4129,6 @@ function buildOptimisticIOUReportAction(
IOUTransactionID: transactionID,
IOUReportID,
type,
- whisperedTo: [CONST.IOU.RECEIPT_STATE.SCANREADY, CONST.IOU.RECEIPT_STATE.SCANNING].some((value) => value === receipt?.state) ? [currentUserAccountID ?? -1] : [],
};
if (type === CONST.IOU.REPORT_ACTION_TYPE.PAY) {
@@ -4342,7 +4339,6 @@ function buildOptimisticReportPreview(
childReportID?: string,
): ReportAction {
const hasReceipt = TransactionUtils.hasReceipt(transaction);
- const isReceiptBeingScanned = hasReceipt && TransactionUtils.isReceiptBeingScanned(transaction);
const message = getReportPreviewMessage(iouReport);
const created = DateUtils.getDBTime();
return {
@@ -4352,7 +4348,6 @@ function buildOptimisticReportPreview(
pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
originalMessage: {
linkedReportID: iouReport?.reportID,
- whisperedTo: isReceiptBeingScanned ? [currentUserAccountID ?? -1] : [],
},
message: [
{
@@ -5202,7 +5197,6 @@ function buildOptimisticMoneyRequestEntities(
paymentType?: PaymentMethodType,
isSettlingUp = false,
isSendMoneyFlow = false,
- receipt: Receipt = {},
isOwnPolicyExpenseChat = false,
isPersonalTrackingExpense?: boolean,
existingTransactionThreadReportID?: string,
@@ -5225,7 +5219,6 @@ function buildOptimisticMoneyRequestEntities(
isPersonalTrackingExpense ? '0' : iouReport.reportID,
isSettlingUp,
isSendMoneyFlow,
- receipt,
isOwnPolicyExpenseChat,
iouActionCreationTime,
linkedTrackedExpenseReportAction,
@@ -5467,7 +5460,7 @@ function shouldReportBeInOptionList({
return false;
}
- if (report?.type === CONST.REPORT.TYPE.PAYCHECK || report?.type === CONST.REPORT.TYPE.BILL) {
+ if ((Object.values(CONST.REPORT.UNSUPPORTED_TYPE) as string[]).includes(report?.type ?? '')) {
return false;
}
@@ -6138,7 +6131,7 @@ function isMoneyRequestReportPendingDeletion(reportOrID: OnyxEntry | str
return parentReportAction?.pendingAction === CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE;
}
-function canUserPerformWriteAction(report: OnyxEntry, reportNameValuePairs?: OnyxEntry) {
+function canUserPerformWriteAction(report: OnyxEntry) {
const reportErrors = getAddWorkspaceRoomOrChatReportErrors(report);
// If the expense report is marked for deletion, let us prevent any further write action.
@@ -6146,6 +6139,7 @@ function canUserPerformWriteAction(report: OnyxEntry, reportNameValuePai
return false;
}
+ const reportNameValuePairs = getReportNameValuePairs(report?.reportID);
return !isArchivedRoom(report, reportNameValuePairs) && isEmptyObject(reportErrors) && report && isAllowedToComment(report) && !isAnonymousUser && canWriteInReport(report);
}
@@ -6940,6 +6934,14 @@ function canJoinChat(report: OnyxInputOrEntry, parentReportAction: OnyxI
* Whether the user can leave a report
*/
function canLeaveChat(report: OnyxEntry, policy: OnyxEntry): boolean {
+ if (isRootGroupChat(report)) {
+ return true;
+ }
+
+ if (isPolicyExpenseChat(report) && !report?.isOwnPolicyExpenseChat && !PolicyUtils.isPolicyAdmin(policy)) {
+ return true;
+ }
+
if (isPublicRoom(report) && SessionUtils.isAnonymousUser()) {
return false;
}
@@ -6949,7 +6951,7 @@ function canLeaveChat(report: OnyxEntry, policy: OnyxEntry): boo
}
// Anyone viewing these chat types is already a participant and therefore cannot leave
- if (isSelfDM(report) || isRootGroupChat(report)) {
+ if (isSelfDM(report)) {
return false;
}
diff --git a/src/libs/SidebarUtils.ts b/src/libs/SidebarUtils.ts
index 37b9f3b881d9..2d609b7279a4 100644
--- a/src/libs/SidebarUtils.ts
+++ b/src/libs/SidebarUtils.ts
@@ -105,6 +105,9 @@ function getOrderedReportIDs(
if (!report) {
return;
}
+ if ((Object.values(CONST.REPORT.UNSUPPORTED_TYPE) as string[]).includes(report?.type ?? '')) {
+ return;
+ }
const reportActions = allReportActions?.[`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${report.reportID}`] ?? {};
const parentReportAction = ReportActionsUtils.getReportAction(report?.parentReportID ?? '-1', report?.parentReportActionID ?? '-1');
const doesReportHaveViolations = OptionsListUtils.shouldShowViolations(report, betas ?? [], transactionViolations);
diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts
index 06465212733c..34b078f7040e 100644
--- a/src/libs/TransactionUtils.ts
+++ b/src/libs/TransactionUtils.ts
@@ -573,8 +573,8 @@ function hasPendingUI(transaction: OnyxEntry, transactionViolations
/**
* Check if the transaction has a defined route
*/
-function hasRoute(transaction: OnyxEntry, isDistanceRequestType: boolean): boolean {
- return !!transaction?.routes?.route0?.geometry?.coordinates || (isDistanceRequestType && !!transaction?.comment?.customUnit?.quantity);
+function hasRoute(transaction: OnyxEntry, isDistanceRequestType?: boolean): boolean {
+ return !!transaction?.routes?.route0?.geometry?.coordinates || (!!isDistanceRequestType && !!transaction?.comment?.customUnit?.quantity);
}
function getAllReportTransactions(reportID?: string, transactions?: OnyxCollection): Transaction[] {
diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts
index 5fedd5443a89..64cae69e0b15 100644
--- a/src/libs/ValidationUtils.ts
+++ b/src/libs/ValidationUtils.ts
@@ -478,6 +478,11 @@ function isExistingTaxName(taxName: string, taxRates: TaxRates): boolean {
return !!Object.values(taxRates).find((taxRate) => taxRate.name === trimmedTaxName);
}
+function isExistingTaxCode(taxCode: string, taxRates: TaxRates): boolean {
+ const trimmedTaxCode = taxCode.trim();
+ return !!Object.keys(taxRates).find((taxID) => taxID === trimmedTaxCode);
+}
+
/**
* Validates the given value if it is correct subscription size.
*/
@@ -528,4 +533,5 @@ export {
isValidReportName,
isExistingTaxName,
isValidSubscriptionSize,
+ isExistingTaxCode,
};
diff --git a/src/libs/actions/App.ts b/src/libs/actions/App.ts
index 988de759d763..2a12b679972a 100644
--- a/src/libs/actions/App.ts
+++ b/src/libs/actions/App.ts
@@ -424,8 +424,6 @@ function setUpPoliciesAndNavigate(session: OnyxEntry) {
if (!isLoggingInAsNewUser && exitTo) {
Navigation.waitForProtectedRoutes()
.then(() => {
- // We must call goBack() to remove the /transition route from history
- Navigation.goBack();
Navigation.navigate(exitTo);
})
.then(endSignOnTransition);
diff --git a/src/libs/actions/IOU.ts b/src/libs/actions/IOU.ts
index d710c06c0d0d..1295d0924617 100644
--- a/src/libs/actions/IOU.ts
+++ b/src/libs/actions/IOU.ts
@@ -1,6 +1,6 @@
import {format} from 'date-fns';
import {fastMerge, Str} from 'expensify-common';
-import type {OnyxCollection, OnyxEntry, OnyxInputValue, OnyxUpdate} from 'react-native-onyx';
+import type {NullishDeep, OnyxCollection, OnyxEntry, OnyxInputValue, OnyxUpdate} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {ValueOf} from 'type-fest';
import ReceiptGeneric from '@assets/images/receipt-generic.png';
@@ -1840,6 +1840,9 @@ function getSendInvoiceInformation(
}
// STEP 5: Build optimistic reportActions.
+ const reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, optimisticInvoiceReport, trimmedComment, optimisticTransaction);
+ optimisticInvoiceReport.parentReportActionID = reportPreviewAction.reportActionID;
+ chatReport.lastVisibleActionCreated = reportPreviewAction.created;
const [optimisticCreatedActionForChat, optimisticCreatedActionForIOUReport, iouAction, optimisticTransactionThread, optimisticCreatedActionForTransactionThread] =
ReportUtils.buildOptimisticMoneyRequestEntities(
optimisticInvoiceReport,
@@ -1853,10 +1856,8 @@ function getSendInvoiceInformation(
undefined,
false,
false,
- receiptObject,
false,
);
- const reportPreviewAction = ReportUtils.buildOptimisticReportPreview(chatReport, optimisticInvoiceReport, trimmedComment, optimisticTransaction);
// STEP 6: Build Onyx Data
const [optimisticData, successData, failureData] = buildOnyxDataForInvoice(
@@ -2033,7 +2034,6 @@ function getMoneyRequestInformation(
undefined,
false,
false,
- receiptObject,
false,
undefined,
linkedTrackedExpenseReportAction?.childReportID,
@@ -2259,7 +2259,6 @@ function getTrackExpenseInformation(
undefined,
false,
false,
- receiptObject,
false,
!shouldUseMoneyReport,
linkedTrackedExpenseReportAction?.childReportID,
@@ -3923,7 +3922,6 @@ function createSplitsAndOnyxData(
'',
false,
false,
- {},
isOwnPolicyExpenseChat,
);
@@ -4504,7 +4502,6 @@ function startSplitBill({
'',
false,
false,
- receiptObject,
isOwnPolicyExpenseChat,
);
@@ -4961,6 +4958,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
tag: transactionTag,
taxCode: transactionTaxCode,
taxAmount: transactionTaxAmount,
+ billable: transactionBillable,
} = ReportUtils.getTransactionDetails(updatedTransaction) ?? {};
const parameters: CompleteSplitBillParams = {
@@ -4975,6 +4973,7 @@ function completeSplitBill(chatReportID: string, reportAction: OnyxTypes.ReportA
splits: JSON.stringify(splits),
taxCode: transactionTaxCode,
taxAmount: transactionTaxAmount,
+ billable: transactionBillable,
};
API.write(WRITE_COMMANDS.COMPLETE_SPLIT_BILL, parameters, {optimisticData, successData, failureData});
@@ -5316,9 +5315,16 @@ function updateMoneyRequestAmountAndCurrency({
API.write(WRITE_COMMANDS.UPDATE_MONEY_REQUEST_AMOUNT_AND_CURRENCY, params, onyxData);
}
-function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
- const allReports = ReportConnection.getAllReports();
+/**
+ *
+ * @param transactionID - The transactionID of IOU
+ * @param reportAction - The reportAction of the transaction in the IOU report
+ * @param isSingleTransactionView - whether we are in the transaction thread report
+ * @return the url to navigate back once the money request is deleted
+ */
+function prepareToCleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
// STEP 1: Get all collections we're updating
+ const allReports = ReportConnection.getAllReports();
const iouReportID = ReportActionsUtils.isMoneyRequestAction(reportAction) ? ReportActionsUtils.getOriginalMessage(reportAction)?.IOUReportID : '-1';
const iouReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReportID}`] ?? null;
const chatReport = allReports?.[`${ONYXKEYS.COLLECTION.REPORT}${iouReport?.chatReportID}`];
@@ -5353,11 +5359,11 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor
},
],
originalMessage: {
- IOUTransactionID: undefined,
+ IOUTransactionID: null,
},
- errors: undefined,
+ errors: null,
},
- } as OnyxTypes.ReportActions;
+ } as Record>;
const lastVisibleAction = ReportActionsUtils.getLastVisibleAction(iouReport?.reportID ?? '-1', updatedReportAction);
const iouReportLastMessageText = ReportActionsUtils.getLastVisibleMessage(iouReport?.reportID ?? '-1', updatedReportAction).lastMessageText;
@@ -5410,7 +5416,199 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor
updatedReportPreviewAction.childMoneyRequestCount = reportPreviewAction.childMoneyRequestCount - 1;
}
- // STEP 5: Build Onyx data
+ // STEP 5: Calculate the url that the user will be navigated back to
+ // This depends on which page they are on and which resources were deleted
+ let reportIDToNavigateBack: string | undefined;
+ if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) {
+ reportIDToNavigateBack = iouReport.reportID;
+ }
+
+ if (iouReport?.chatReportID && shouldDeleteIOUReport) {
+ reportIDToNavigateBack = iouReport.chatReportID;
+ }
+
+ const urlToNavigateBack = reportIDToNavigateBack ? ROUTES.REPORT_WITH_ID.getRoute(reportIDToNavigateBack) : undefined;
+
+ return {
+ shouldDeleteTransactionThread,
+ shouldDeleteIOUReport,
+ updatedReportAction,
+ updatedIOUReport,
+ updatedReportPreviewAction,
+ transactionThreadID,
+ transactionThread,
+ chatReport,
+ transaction,
+ transactionViolations,
+ reportPreviewAction,
+ iouReport,
+ urlToNavigateBack,
+ };
+}
+
+/**
+ *
+ * @param transactionID - The transactionID of IOU
+ * @param reportAction - The reportAction of the transaction in the IOU report
+ * @param isSingleTransactionView - whether we are in the transaction thread report
+ * @return the url to navigate back once the money request is deleted
+ */
+function cleanUpMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
+ const {
+ shouldDeleteTransactionThread,
+ shouldDeleteIOUReport,
+ updatedReportAction,
+ updatedIOUReport,
+ updatedReportPreviewAction,
+ transactionThreadID,
+ chatReport,
+ iouReport,
+ reportPreviewAction,
+ urlToNavigateBack,
+ } = prepareToCleanUpMoneyRequest(transactionID, reportAction, isSingleTransactionView);
+
+ // build Onyx data
+
+ // Onyx operations to delete the transaction, update the IOU report action and chat report action
+ const onyxUpdates: OnyxUpdate[] = [
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
+ value: null,
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
+ value: {
+ [reportAction.reportActionID]: shouldDeleteIOUReport
+ ? null
+ : {
+ pendingAction: null,
+ },
+ },
+ },
+ ];
+
+ if (reportPreviewAction?.reportActionID) {
+ onyxUpdates.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${chatReport?.reportID}`,
+ value: {
+ [reportPreviewAction.reportActionID]: {
+ ...updatedReportPreviewAction,
+ pendingAction: null,
+ errors: null,
+ },
+ },
+ });
+ }
+
+ // added the operation to delete associated transaction violations
+ if (Permissions.canUseViolations(betas)) {
+ onyxUpdates.push({
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
+ value: null,
+ });
+ }
+
+ // added the operation to delete transaction thread
+ if (shouldDeleteTransactionThread) {
+ onyxUpdates.push(
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${transactionThreadID}`,
+ value: null,
+ },
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${transactionThreadID}`,
+ value: null,
+ },
+ );
+ }
+
+ // added operations to update IOU report and chat report
+ onyxUpdates.push(
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${iouReport?.reportID}`,
+ value: updatedReportAction,
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
+ value: updatedIOUReport,
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
+ value: ReportUtils.getOutstandingChildRequest(updatedIOUReport),
+ },
+ );
+
+ if (!shouldDeleteIOUReport && updatedReportPreviewAction.childMoneyRequestCount === 0) {
+ onyxUpdates.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
+ value: {
+ hasOutstandingChildRequest: false,
+ },
+ });
+ }
+
+ if (shouldDeleteIOUReport) {
+ onyxUpdates.push(
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${chatReport?.reportID}`,
+ value: {
+ hasOutstandingChildRequest: false,
+ iouReportID: null,
+ lastMessageText: ReportActionsUtils.getLastVisibleMessage(iouReport?.chatReportID ?? '-1', {[reportPreviewAction?.reportActionID ?? '-1']: null})?.lastMessageText,
+ lastVisibleActionCreated: ReportActionsUtils.getLastVisibleAction(iouReport?.chatReportID ?? '-1', {[reportPreviewAction?.reportActionID ?? '-1']: null})?.created,
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${iouReport?.reportID}`,
+ value: null,
+ },
+ );
+ }
+
+ Onyx.update(onyxUpdates);
+
+ return urlToNavigateBack;
+}
+
+/**
+ *
+ * @param transactionID - The transactionID of IOU
+ * @param reportAction - The reportAction of the transaction in the IOU report
+ * @param isSingleTransactionView - whether we are in the transaction thread report
+ * @return the url to navigate back once the money request is deleted
+ */
+function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
+ // STEP 1: Calculate and prepare the data
+ const {
+ shouldDeleteTransactionThread,
+ shouldDeleteIOUReport,
+ updatedReportAction,
+ updatedIOUReport,
+ updatedReportPreviewAction,
+ transactionThreadID,
+ transactionThread,
+ chatReport,
+ transaction,
+ transactionViolations,
+ iouReport,
+ reportPreviewAction,
+ urlToNavigateBack,
+ } = prepareToCleanUpMoneyRequest(transactionID, reportAction, isSingleTransactionView);
+
+ // STEP 2: Build Onyx data
+ // The logic mostly resembles the cleanUpMoneyRequest function
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.SET,
@@ -5611,20 +5809,11 @@ function deleteMoneyRequest(transactionID: string, reportAction: OnyxTypes.Repor
reportActionID: reportAction.reportActionID,
};
- // STEP 6: Make the API request
+ // STEP 3: Make the API request
API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST, parameters, {optimisticData, successData, failureData});
CachedPDFPaths.clearByKey(transactionID);
- // STEP 7: Navigate the user depending on which page they are on and which resources were deleted
- if (iouReport && isSingleTransactionView && shouldDeleteTransactionThread && !shouldDeleteIOUReport) {
- // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
- return ROUTES.REPORT_WITH_ID.getRoute(iouReport.reportID);
- }
-
- if (iouReport?.chatReportID && shouldDeleteIOUReport) {
- // Pop the deleted report screen before navigating. This prevents navigating to the Concierge chat due to the missing report.
- return ROUTES.REPORT_WITH_ID.getRoute(iouReport.chatReportID);
- }
+ return urlToNavigateBack;
}
function deleteTrackExpense(chatReportID: string, transactionID: string, reportAction: OnyxTypes.ReportAction, isSingleTransactionView = false) {
@@ -6813,13 +7002,12 @@ function replaceReceipt(transactionID: string, file: File, source: string) {
},
},
];
-
const failureData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.TRANSACTION}${transactionID}`,
value: {
- receipt: oldReceipt,
+ receipt: !isEmptyObject(oldReceipt) ? oldReceipt : null,
filename: transaction?.filename,
errors: getReceiptError(receiptOptimistic, file.name),
},
@@ -7060,6 +7248,7 @@ function putOnHold(transactionID: string, comment: string, reportID: string) {
*/
function unholdRequest(transactionID: string, reportID: string) {
const createdReportAction = ReportUtils.buildOptimisticUnHoldReportAction();
+ const transactionViolations = allTransactionViolations[`${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`];
const optimisticData: OnyxUpdate[] = [
{
@@ -7079,6 +7268,11 @@ function unholdRequest(transactionID: string, reportID: string) {
},
},
},
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
+ value: transactionViolations?.filter((violation) => violation.name !== CONST.VIOLATIONS.HOLD) ?? [],
+ },
];
const successData: OnyxUpdate[] = [
@@ -7103,6 +7297,11 @@ function unholdRequest(transactionID: string, reportID: string) {
errors: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('iou.error.genericUnholdExpenseFailureMessage'),
},
},
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION_VIOLATIONS}${transactionID}`,
+ value: transactionViolations ?? null,
+ },
];
API.write(
@@ -7153,11 +7352,12 @@ function getIOURequestPolicyID(transaction: OnyxEntry, re
}
export {
+ adjustRemainingSplitShares,
approveMoneyRequest,
- unapproveExpenseReport,
canApproveIOU,
- canIOUBePaid,
cancelPayment,
+ canIOUBePaid,
+ cleanUpMoneyRequest,
clearMoneyRequest,
completeSplitBill,
createDistanceRequest,
@@ -7165,19 +7365,24 @@ export {
deleteMoneyRequest,
deleteTrackExpense,
detachReceipt,
+ dismissHoldUseExplanation,
editMoneyRequest,
+ getIOURequestPolicyID,
initMoneyRequest,
navigateToStartStepIfScanFileCannotBeRead,
- payMoneyRequest,
payInvoice,
+ payMoneyRequest,
putOnHold,
replaceReceipt,
requestMoney,
+ resetSplitShares,
savePreferredPaymentMethod,
+ sendInvoice,
sendMoneyElsewhere,
sendMoneyWithWallet,
setCustomUnitRateID,
setDraftSplitTransaction,
+ setIndividualShare,
setMoneyRequestAmount,
setMoneyRequestBillable,
setMoneyRequestCategory,
@@ -7189,34 +7394,29 @@ export {
setMoneyRequestParticipantsFromReport,
setMoneyRequestPendingFields,
setMoneyRequestReceipt,
- setSplitPayer,
setMoneyRequestTag,
setMoneyRequestTaxAmount,
setMoneyRequestTaxRate,
- dismissHoldUseExplanation,
- updateMoneyRequestDate,
+ setSplitPayer,
setSplitShares,
- resetSplitShares,
- setIndividualShare,
- adjustRemainingSplitShares,
splitBill,
splitBillAndOpenReport,
startMoneyRequest,
startSplitBill,
submitReport,
trackExpense,
+ unapproveExpenseReport,
unholdRequest,
updateDistanceRequestRate,
updateMoneyRequestAmountAndCurrency,
updateMoneyRequestBillable,
updateMoneyRequestCategory,
+ updateMoneyRequestDate,
updateMoneyRequestDescription,
updateMoneyRequestDistance,
updateMoneyRequestMerchant,
updateMoneyRequestTag,
updateMoneyRequestTaxAmount,
updateMoneyRequestTaxRate,
- sendInvoice,
- getIOURequestPolicyID,
};
export type {GPSPoint as GpsPoint, IOURequestType};
diff --git a/src/libs/actions/OnyxUpdates.ts b/src/libs/actions/OnyxUpdates.ts
index 91cdde6a7c64..73c8b3d592bf 100644
--- a/src/libs/actions/OnyxUpdates.ts
+++ b/src/libs/actions/OnyxUpdates.ts
@@ -163,10 +163,15 @@ function doesClientNeedToBeUpdated(previousUpdateID = 0, clientLastUpdateID = 0)
// If we don't have any value in lastUpdateIDFromClient, this is the first time we're receiving anything, so we need to do a last reconnectApp
if (!lastUpdateIDFromClient) {
+ Log.info('We do not have lastUpdateIDFromClient, client needs updating');
+ return true;
+ }
+ if (lastUpdateIDFromClient < previousUpdateID) {
+ Log.info('lastUpdateIDFromClient is less than the previousUpdateID received, client needs updating', false, {lastUpdateIDFromClient, previousUpdateID});
return true;
}
- return lastUpdateIDFromClient < previousUpdateID;
+ return false;
}
// eslint-disable-next-line import/prefer-default-export
diff --git a/src/libs/actions/Policy/Policy.ts b/src/libs/actions/Policy/Policy.ts
index 561c98362e27..c5be4b6074a7 100644
--- a/src/libs/actions/Policy/Policy.ts
+++ b/src/libs/actions/Policy/Policy.ts
@@ -260,6 +260,7 @@ function deleteWorkspace(policyID: string, policyName: string) {
(report) => report?.policyID === policyID && (ReportUtils.isChatRoom(report) || ReportUtils.isPolicyExpenseChat(report) || ReportUtils.isTaskReport(report)),
);
const finallyData: OnyxUpdate[] = [];
+ const currentTime = DateUtils.getDBTime();
reportsToArchive.forEach((report) => {
const {reportID, ownerAccountID} = report ?? {};
optimisticData.push({
@@ -270,6 +271,8 @@ function deleteWorkspace(policyID: string, policyName: string) {
statusNum: CONST.REPORT.STATUS_NUM.CLOSED,
oldPolicyName: allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`]?.name ?? '',
policyName: '',
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ private_isArchived: currentTime,
},
});
@@ -343,13 +346,32 @@ function deleteWorkspace(policyID: string, policyName: string) {
function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf) {
const policy = getPolicy(policyID);
+ const wasPolicyOnManualReporting = PolicyUtils.getCorrectedAutoReportingFrequency(policy) === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL;
+
const optimisticData: OnyxUpdate[] = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
- autoReportingFrequency: frequency,
+ // Recall that the "daily" and "manual" frequencies don't actually exist in Onyx or the DB (see PolicyUtils.getCorrectedAutoReportingFrequency)
+ autoReportingFrequency: frequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL ? CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE : frequency,
pendingFields: {autoReportingFrequency: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
+
+ // To set the frequency to "manual", we really must set it to "immediate" with harvesting disabled
+ ...(frequency === CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL && {
+ harvesting: {
+ enabled: false,
+ },
+ }),
+
+ // If the policy was on manual reporting before, and now will be auto-reported,
+ // then we must re-enable harvesting
+ ...(wasPolicyOnManualReporting &&
+ frequency !== CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL && {
+ harvesting: {
+ enabled: true,
+ },
+ }),
},
},
];
@@ -360,6 +382,7 @@ function setWorkspaceAutoReportingFrequency(policyID: string, frequency: ValueOf
key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
value: {
autoReportingFrequency: policy?.autoReportingFrequency ?? null,
+ harvesting: policy?.harvesting ?? null,
pendingFields: {autoReportingFrequency: null},
errorFields: {autoReportingFrequency: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workflowsDelayedSubmissionPage.autoReportingFrequencyErrorMessage')},
},
@@ -3066,8 +3089,11 @@ function upgradeToCorporate(policyID: string, featureName: string) {
glCodes: true,
...(PolicyUtils.isInstantSubmitEnabled(policy) && {
autoReporting: true,
- autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.MANUAL,
+ autoReportingFrequency: CONST.POLICY.AUTO_REPORTING_FREQUENCIES.IMMEDIATE,
}),
+ harvesting: {
+ enabled: false,
+ },
},
},
];
@@ -3095,6 +3121,7 @@ function upgradeToCorporate(policyID: string, featureName: string) {
glCodes: policy?.glCodes ?? null,
autoReporting: policy?.autoReporting ?? null,
autoReportingFrequency: policy?.autoReportingFrequency ?? null,
+ harvesting: policy?.harvesting ?? null,
},
},
];
diff --git a/src/libs/actions/Report.ts b/src/libs/actions/Report.ts
index 035d3c13d137..6758859eab47 100644
--- a/src/libs/actions/Report.ts
+++ b/src/libs/actions/Report.ts
@@ -55,6 +55,7 @@ import {prepareDraftComment} from '@libs/DraftCommentUtils';
import * as EmojiUtils from '@libs/EmojiUtils';
import * as Environment from '@libs/Environment/Environment';
import * as ErrorUtils from '@libs/ErrorUtils';
+import HttpUtils from '@libs/HttpUtils';
import isPublicScreenRoute from '@libs/isPublicScreenRoute';
import * as Localize from '@libs/Localize';
import Log from '@libs/Log';
@@ -3228,7 +3229,7 @@ function completeOnboarding(
: task.description;
const currentTask = ReportUtils.buildOptimisticTaskReport(
actorAccountID,
- undefined,
+ currentUserAccountID,
targetChatReportID,
task.title,
taskDescription,
@@ -3591,6 +3592,11 @@ function searchForReports(searchInput: string, policyID?: string) {
const searchForRoomToMentionParams: SearchForRoomsToMentionParams = {query: searchInput, policyID: policyID ?? '-1'};
const searchForReportsParams: SearchForReportsParams = {searchInput, canCancel: true};
+ // We want to cancel all pending SearchForReports API calls before making another one
+ if (!policyID) {
+ HttpUtils.cancelPendingRequests(READ_COMMANDS.SEARCH_FOR_REPORTS);
+ }
+
API.read(policyID ? READ_COMMANDS.SEARCH_FOR_ROOMS_TO_MENTION : READ_COMMANDS.SEARCH_FOR_REPORTS, policyID ? searchForRoomToMentionParams : searchForReportsParams, {
successData,
failureData,
diff --git a/src/libs/actions/Search.ts b/src/libs/actions/Search.ts
index 4ce82a027a12..969812b02b02 100644
--- a/src/libs/actions/Search.ts
+++ b/src/libs/actions/Search.ts
@@ -3,6 +3,10 @@ import type {OnyxUpdate} from 'react-native-onyx';
import * as API from '@libs/API';
import type {SearchParams} from '@libs/API/parameters';
import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types';
+import * as ApiUtils from '@libs/ApiUtils';
+import fileDownload from '@libs/fileDownload';
+import enhanceParameters from '@libs/Network/enhanceParameters';
+import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import type {SearchTransaction} from '@src/types/onyx/SearchResults';
import * as Report from './Report';
@@ -83,4 +87,25 @@ function deleteMoneyRequestOnSearch(hash: number, transactionIDList: string[]) {
API.write(WRITE_COMMANDS.DELETE_MONEY_REQUEST_ON_SEARCH, {hash, transactionIDList}, {optimisticData, finallyData});
}
-export {search, createTransactionThread, deleteMoneyRequestOnSearch, holdMoneyRequestOnSearch, unholdMoneyRequestOnSearch};
+type Params = Record;
+
+function exportSearchItemsToCSV(query: string, reportIDList: Array | undefined, transactionIDList: string[], policyIDs: string[], onDownloadFailed: () => void) {
+ const finalParameters = enhanceParameters(WRITE_COMMANDS.EXPORT_SEARCH_ITEMS_TO_CSV, {
+ query,
+ reportIDList,
+ transactionIDList,
+ policyIDs,
+ }) as Params;
+
+ const formData = new FormData();
+ Object.entries(finalParameters).forEach(([key, value]) => {
+ if (Array.isArray(value)) {
+ formData.append(key, value.join(','));
+ } else {
+ formData.append(key, String(value));
+ }
+ });
+
+ fileDownload(ApiUtils.getCommandURL({command: WRITE_COMMANDS.EXPORT_SEARCH_ITEMS_TO_CSV}), 'Expensify.csv', '', false, formData, CONST.NETWORK.METHOD.POST, onDownloadFailed);
+}
+export {search, createTransactionThread, deleteMoneyRequestOnSearch, holdMoneyRequestOnSearch, unholdMoneyRequestOnSearch, exportSearchItemsToCSV};
diff --git a/src/libs/actions/Session/index.ts b/src/libs/actions/Session/index.ts
index 371e60959b70..f30e2566f650 100644
--- a/src/libs/actions/Session/index.ts
+++ b/src/libs/actions/Session/index.ts
@@ -37,7 +37,6 @@ import * as ReportUtils from '@libs/ReportUtils';
import * as SessionUtils from '@libs/SessionUtils';
import Timers from '@libs/Timers';
import {hideContextMenu} from '@pages/home/report/ContextMenu/ReportActionContextMenu';
-import {KEYS_TO_PRESERVE, openApp} from '@userActions/App';
import * as Device from '@userActions/Device';
import * as PriorityMode from '@userActions/PriorityMode';
import redirectToSignIn from '@userActions/SignInRedirect';
@@ -53,7 +52,6 @@ import type Credentials from '@src/types/onyx/Credentials';
import type {AutoAuthState} from '@src/types/onyx/Session';
import type Session from '@src/types/onyx/Session';
import clearCache from './clearCache';
-import updateSessionAuthTokens from './updateSessionAuthTokens';
let session: Session = {};
let authPromiseResolver: ((value: boolean) => void) | null = null;
@@ -944,25 +942,7 @@ function validateTwoFactorAuth(twoFactorAuthCode: string) {
const params: ValidateTwoFactorAuthParams = {twoFactorAuthCode};
- // eslint-disable-next-line rulesdir/no-api-side-effects-method
- API.makeRequestWithSideEffects(SIDE_EFFECT_REQUEST_COMMANDS.TWO_FACTOR_AUTH_VALIDATE, params, {optimisticData, successData, failureData}).then((response) => {
- if (!response?.authToken) {
- return;
- }
-
- const keysToPreserveWithPrivatePersonalDetails = [...KEYS_TO_PRESERVE, ONYXKEYS.PRIVATE_PERSONAL_DETAILS];
- Onyx.clear(keysToPreserveWithPrivatePersonalDetails).then(() => {
- // Update authToken in Onyx and in our local variables so that API requests will use the new authToken
- updateSessionAuthTokens(response.authToken, response.encryptedAuthToken);
-
- // Note: It is important to manually set the authToken that is in the store here since
- // reconnectApp will immediate post and use the local authToken. Onyx updates subscribers lately so it is not
- // enough to do the updateSessionAuthTokens() call above.
- NetworkStore.setAuthToken(response.authToken ?? null);
-
- openApp();
- });
- });
+ API.write(WRITE_COMMANDS.TWO_FACTOR_AUTH_VALIDATE, params, {optimisticData, successData, failureData});
}
/**
diff --git a/src/libs/actions/Task.ts b/src/libs/actions/Task.ts
index 8dcb6128b143..c4e1e5de81df 100644
--- a/src/libs/actions/Task.ts
+++ b/src/libs/actions/Task.ts
@@ -922,7 +922,7 @@ function deleteTask(report: OnyxEntry) {
// If the task report is the last visible action in the parent report, we should navigate back to the parent report
const shouldDeleteTaskReport = !ReportActionsUtils.doesReportHaveVisibleActions(report.reportID ?? '-1');
const optimisticReportAction: Partial = {
- pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
+ pendingAction: shouldDeleteTaskReport ? CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE : CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
previousMessage: parentReportAction?.message,
message: [
{
diff --git a/src/libs/actions/TaxRate.ts b/src/libs/actions/TaxRate.ts
index 4792304cb9ce..0e7245a93f7b 100644
--- a/src/libs/actions/TaxRate.ts
+++ b/src/libs/actions/TaxRate.ts
@@ -2,7 +2,14 @@ import type {OnyxCollection} from 'react-native-onyx';
import Onyx from 'react-native-onyx';
import type {FormOnyxValues} from '@components/Form/types';
import * as API from '@libs/API';
-import type {CreatePolicyTaxParams, DeletePolicyTaxesParams, RenamePolicyTaxParams, SetPolicyTaxesEnabledParams, UpdatePolicyTaxValueParams} from '@libs/API/parameters';
+import type {
+ CreatePolicyTaxParams,
+ DeletePolicyTaxesParams,
+ RenamePolicyTaxParams,
+ SetPolicyTaxesEnabledParams,
+ UpdatePolicyTaxCodeParams,
+ UpdatePolicyTaxValueParams,
+} from '@libs/API/parameters';
import {WRITE_COMMANDS} from '@libs/API/types';
import {translateLocal} from '@libs/Localize';
import * as ValidationUtils from '@libs/ValidationUtils';
@@ -10,6 +17,8 @@ import CONST from '@src/CONST';
import * as ErrorUtils from '@src/libs/ErrorUtils';
import ONYXKEYS from '@src/ONYXKEYS';
import INPUT_IDS from '@src/types/form/WorkspaceNewTaxForm';
+// eslint-disable-next-line import/no-named-default
+import {default as INPUT_IDS_TAX_CODE} from '@src/types/form/WorkspaceTaxCodeForm';
import type {Policy, TaxRate, TaxRates} from '@src/types/onyx';
import type * as OnyxCommon from '@src/types/onyx/OnyxCommon';
import type {OnyxData} from '@src/types/onyx/Request';
@@ -46,6 +55,17 @@ const validateTaxName = (policy: Policy, values: FormOnyxValues) => {
+ const errors = ValidationUtils.getFieldRequiredErrors(values, [INPUT_IDS_TAX_CODE.TAX_CODE]);
+
+ const taxCode = values[INPUT_IDS_TAX_CODE.TAX_CODE];
+ if (policy?.taxRates?.taxes && ValidationUtils.isExistingTaxCode(taxCode, policy.taxRates.taxes)) {
+ errors[INPUT_IDS_TAX_CODE.TAX_CODE] = translateLocal('workspace.taxes.error.taxCodeAlreadyExists');
+ }
+
+ return errors;
+};
+
/**
* Function to validate tax value
*/
@@ -463,6 +483,82 @@ function renamePolicyTax(policyID: string, taxID: string, newName: string) {
API.write(WRITE_COMMANDS.RENAME_POLICY_TAX, parameters, onyxData);
}
+function setPolicyTaxCode(policyID: string, oldTaxCode: string, newTaxCode: string) {
+ const policy = allPolicies?.[`${ONYXKEYS.COLLECTION.POLICY}${policyID}`];
+ const originalTaxRate = {...policy?.taxRates?.taxes[oldTaxCode]};
+ const onyxData: OnyxData = {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ value: {
+ taxRates: {
+ taxes: {
+ [oldTaxCode]: null,
+ [newTaxCode]: {
+ ...originalTaxRate,
+ pendingFields: {code: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE},
+ pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.UPDATE,
+ errorFields: {code: null},
+ previousTaxCode: oldTaxCode,
+ },
+ },
+ },
+ },
+ },
+ ],
+ successData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ value: {
+ taxRates: {
+ taxes: {
+ [oldTaxCode]: null,
+ [newTaxCode]: {
+ ...originalTaxRate,
+ code: newTaxCode,
+ pendingFields: {code: null},
+ pendingAction: null,
+ errorFields: {code: null},
+ },
+ },
+ },
+ },
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`,
+ value: {
+ taxRates: {
+ taxes: {
+ [newTaxCode]: null,
+ [oldTaxCode]: {
+ ...originalTaxRate,
+ code: originalTaxRate.code,
+ pendingFields: {code: null},
+ pendingAction: null,
+ errorFields: {code: ErrorUtils.getMicroSecondOnyxErrorWithTranslationKey('workspace.taxes.error.updateFailureMessage')},
+ },
+ },
+ },
+ },
+ },
+ ],
+ };
+
+ const parameters: UpdatePolicyTaxCodeParams = {
+ policyID,
+ oldTaxCode,
+ newTaxCode,
+ taxID: originalTaxRate.name ?? '',
+ };
+
+ API.write(WRITE_COMMANDS.UPDATE_POLICY_TAX_CODE, parameters, onyxData);
+}
+
export {
createPolicyTax,
getNextTaxCode,
@@ -471,8 +567,10 @@ export {
getTaxValueWithPercentage,
setPolicyTaxesEnabled,
validateTaxName,
+ validateTaxCode,
validateTaxValue,
deletePolicyTaxes,
updatePolicyTaxValue,
renamePolicyTax,
+ setPolicyTaxCode,
};
diff --git a/src/libs/actions/Transaction.ts b/src/libs/actions/Transaction.ts
index 8f81b7d3ea5c..50b129f53295 100644
--- a/src/libs/actions/Transaction.ts
+++ b/src/libs/actions/Transaction.ts
@@ -444,4 +444,31 @@ function markAsCash(transactionID: string, transactionThreadReportID: string) {
return API.write(WRITE_COMMANDS.MARK_AS_CASH, parameters, onyxData);
}
-export {addStop, createInitialWaypoints, saveWaypoint, removeWaypoint, getRoute, updateWaypoints, clearError, markAsCash, dismissDuplicateTransactionViolation, setReviewDuplicatesKey};
+function openDraftDistanceExpense() {
+ const onyxData: OnyxData = {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: ONYXKEYS.NVP_RECENT_WAYPOINTS,
+
+ // By optimistically setting the recent waypoints to an empty array, no further loading attempts will be made
+ value: [],
+ },
+ ],
+ };
+ API.read(READ_COMMANDS.OPEN_DRAFT_DISTANCE_EXPENSE, null, onyxData);
+}
+
+export {
+ addStop,
+ createInitialWaypoints,
+ saveWaypoint,
+ removeWaypoint,
+ getRoute,
+ updateWaypoints,
+ clearError,
+ markAsCash,
+ dismissDuplicateTransactionViolation,
+ setReviewDuplicatesKey,
+ openDraftDistanceExpense,
+};
diff --git a/src/libs/fileDownload/index.ts b/src/libs/fileDownload/index.ts
index b39e65a87f94..133a18e146a5 100644
--- a/src/libs/fileDownload/index.ts
+++ b/src/libs/fileDownload/index.ts
@@ -9,7 +9,7 @@ import type {FileDownload} from './types';
* The function downloads an attachment on web/desktop platforms.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
-const fileDownload: FileDownload = (url, fileName, successMessage = '', shouldOpenExternalLink = false) => {
+const fileDownload: FileDownload = (url, fileName, successMessage = '', shouldOpenExternalLink = false, formData = undefined, requestType = 'get', onDownloadFailed?: () => void) => {
const resolvedUrl = tryResolveUrlFromApiRoot(url);
if (
// we have two file download cases that we should allow 1. dowloading attachments 2. downloading Expensify package for Sage Intacct
@@ -24,7 +24,12 @@ const fileDownload: FileDownload = (url, fileName, successMessage = '', shouldOp
return Promise.resolve();
}
- return fetch(url)
+ const fetchOptions: RequestInit = {
+ method: requestType,
+ body: formData,
+ };
+
+ return fetch(url, fetchOptions)
.then((response) => response.blob())
.then((blob) => {
// Create blob link to download
@@ -50,8 +55,12 @@ const fileDownload: FileDownload = (url, fileName, successMessage = '', shouldOp
link.parentNode?.removeChild(link);
})
.catch(() => {
- // file could not be downloaded, open sourceURL in new tab
- Link.openExternalLink(url);
+ if (onDownloadFailed) {
+ onDownloadFailed();
+ } else {
+ // file could not be downloaded, open sourceURL in new tab
+ Link.openExternalLink(url);
+ }
});
};
diff --git a/src/libs/fileDownload/types.ts b/src/libs/fileDownload/types.ts
index fcc210c1c42f..6b8c1fe6be72 100644
--- a/src/libs/fileDownload/types.ts
+++ b/src/libs/fileDownload/types.ts
@@ -1,7 +1,15 @@
import type {Asset} from 'react-native-image-picker';
+import type {RequestType} from '@src/types/onyx/Request';
-type FileDownload = (url: string, fileName?: string, successMessage?: string, shouldOpenExternalLink?: boolean) => Promise;
-
+type FileDownload = (
+ url: string,
+ fileName?: string,
+ successMessage?: string,
+ shouldOpenExternalLink?: boolean,
+ formData?: FormData,
+ requestType?: RequestType,
+ onDownloadFailed?: () => void,
+) => Promise;
type ImageResolution = {width: number; height: number};
type GetImageResolution = (url: File | Asset) => Promise;
diff --git a/src/pages/ReportDetailsPage.tsx b/src/pages/ReportDetailsPage.tsx
index 284004bc29ca..f66d44ee9a3b 100644
--- a/src/pages/ReportDetailsPage.tsx
+++ b/src/pages/ReportDetailsPage.tsx
@@ -133,6 +133,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
const chatRoomSubtitle = useMemo(() => ReportUtils.getChatRoomSubtitle(report), [report, policy]);
const isSystemChat = useMemo(() => ReportUtils.isSystemChat(report), [report]);
const isGroupChat = useMemo(() => ReportUtils.isGroupChat(report), [report]);
+ const isRootGroupChat = useMemo(() => ReportUtils.isRootGroupChat(report), [report]);
const isThread = useMemo(() => ReportUtils.isThread(report), [report]);
const participants = useMemo(() => {
const shouldExcludeHiddenParticipants = !isGroupChat && !isSystemChat;
@@ -217,13 +218,13 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
const leaveChat = useCallback(() => {
Navigation.dismissModal();
- if (isChatRoom) {
- const isWorkspaceMemberLeavingWorkspaceRoom = (report.visibility === CONST.REPORT.VISIBILITY.RESTRICTED || isPolicyExpenseChat) && isPolicyEmployee;
- Report.leaveRoom(report.reportID, isWorkspaceMemberLeavingWorkspaceRoom);
+ if (isRootGroupChat) {
+ Report.leaveGroupChat(report.reportID);
return;
}
- Report.leaveGroupChat(report.reportID);
- }, [isChatRoom, isPolicyEmployee, isPolicyExpenseChat, report.reportID, report.visibility]);
+ const isWorkspaceMemberLeavingWorkspaceRoom = (report.visibility === CONST.REPORT.VISIBILITY.RESTRICTED || isPolicyExpenseChat) && isPolicyEmployee;
+ Report.leaveRoom(report.reportID, isWorkspaceMemberLeavingWorkspaceRoom);
+ }, [isPolicyEmployee, isPolicyExpenseChat, isRootGroupChat, report.reportID, report.visibility]);
const unapproveExpenseReportOrShowModal = useCallback(() => {
if (PolicyUtils.hasAccountingConnections(policy)) {
@@ -234,8 +235,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
IOU.unapproveExpenseReport(moneyRequestReport);
}, [moneyRequestReport, policy]);
- const shouldShowLeaveButton =
- !isThread && (isGroupChat || (isChatRoom && ReportUtils.canLeaveChat(report, policy)) || (isPolicyExpenseChat && !report.isOwnPolicyExpenseChat && !isPolicyAdmin));
+ const shouldShowLeaveButton = ReportUtils.canLeaveChat(report, policy);
const reportName = ReportUtils.isDeprecatedGroupDM(report) || isGroupChat ? ReportUtils.getGroupChatName(undefined, false, report) : ReportUtils.getReportName(report);
@@ -382,7 +382,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
icon: Expensicons.Exit,
isAnonymousAction: true,
action: () => {
- if (ReportUtils.getParticipantsAccountIDsForDisplay(report, false, true).length === 1 && isGroupChat) {
+ if (ReportUtils.getParticipantsAccountIDsForDisplay(report, false, true).length === 1 && isRootGroupChat) {
setIsLastMemberLeavingGroupModalVisible(true);
return;
}
@@ -418,6 +418,7 @@ function ReportDetailsPage({policies, report, session, personalDetails}: ReportD
isSelfDM,
isArchivedRoom,
isGroupChat,
+ isRootGroupChat,
isDefaultRoom,
isChatThread,
isPolicyEmployee,
diff --git a/src/pages/RestrictedAction/Workspace/WorkspaceOwnerRestrictedAction.tsx b/src/pages/RestrictedAction/Workspace/WorkspaceOwnerRestrictedAction.tsx
index 52156c05a873..94462c92f17c 100644
--- a/src/pages/RestrictedAction/Workspace/WorkspaceOwnerRestrictedAction.tsx
+++ b/src/pages/RestrictedAction/Workspace/WorkspaceOwnerRestrictedAction.tsx
@@ -21,7 +21,7 @@ function WorkspaceOwnerRestrictedAction() {
const addPaymentCard = () => {
Navigation.closeRHPFlow();
- Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION);
+ Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION_ADD_PAYMENT_CARD);
};
return (
diff --git a/src/pages/Search/AdvancedSearchFilters.tsx b/src/pages/Search/AdvancedSearchFilters.tsx
new file mode 100644
index 000000000000..171e2c45dbd7
--- /dev/null
+++ b/src/pages/Search/AdvancedSearchFilters.tsx
@@ -0,0 +1,58 @@
+import React, {useMemo} from 'react';
+import {View} from 'react-native';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
+import useLocalize from '@hooks/useLocalize';
+import useSingleExecution from '@hooks/useSingleExecution';
+import useWaitForNavigation from '@hooks/useWaitForNavigation';
+import Navigation from '@libs/Navigation/Navigation';
+import ROUTES from '@src/ROUTES';
+
+function getFilterDisplayTitle(filters: Record, fieldName: string) {
+ // This is temporary because the full parsing of search query is not yet done
+ // TODO once we have values from query, this value should be `filters[fieldName].value`
+ return fieldName;
+}
+
+function AdvancedSearchFilters() {
+ const {translate} = useLocalize();
+ const {singleExecution} = useSingleExecution();
+ const waitForNavigate = useWaitForNavigation();
+
+ const advancedFilters = useMemo(
+ () => [
+ {
+ title: getFilterDisplayTitle({}, 'title'),
+ description: 'common.type' as const,
+ route: ROUTES.SEARCH_ADVANCED_FILTERS_TYPE,
+ },
+ {
+ title: getFilterDisplayTitle({}, 'date'),
+ description: 'common.date' as const,
+ route: ROUTES.SEARCH_ADVANCED_FILTERS_DATE,
+ },
+ ],
+ [],
+ );
+
+ return (
+
+ {advancedFilters.map((item) => {
+ const onPress = singleExecution(waitForNavigate(() => Navigation.navigate(item.route)));
+
+ return (
+
+ );
+ })}
+
+ );
+}
+
+AdvancedSearchFilters.displayName = 'AdvancedSearchFilters';
+
+export default AdvancedSearchFilters;
diff --git a/src/pages/Search/SearchAdvancedFiltersPage.tsx b/src/pages/Search/SearchAdvancedFiltersPage.tsx
new file mode 100644
index 000000000000..9d4864bce8eb
--- /dev/null
+++ b/src/pages/Search/SearchAdvancedFiltersPage.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import AdvancedSearchFilters from './AdvancedSearchFilters';
+
+function SearchAdvancedFiltersPage() {
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+
+ return (
+
+
+
+
+
+
+ );
+}
+
+SearchAdvancedFiltersPage.displayName = 'SearchAdvancedFiltersPage';
+
+export default SearchAdvancedFiltersPage;
diff --git a/src/pages/Search/SearchFilters.tsx b/src/pages/Search/SearchFilters.tsx
index bbb861364f00..0728743c1875 100644
--- a/src/pages/Search/SearchFilters.tsx
+++ b/src/pages/Search/SearchFilters.tsx
@@ -25,6 +25,7 @@ type SearchMenuFilterItem = {
route: Route;
};
+// Because we will add have AdvancedFilters, in future rename this component to `SearchTypeMenu|Tabs|Filters` to avoid confusion
function SearchFilters({query}: SearchFiltersProps) {
const styles = useThemeStyles();
const {isSmallScreenWidth} = useWindowDimensions();
diff --git a/src/pages/Search/SearchFiltersDatePage.tsx b/src/pages/Search/SearchFiltersDatePage.tsx
new file mode 100644
index 000000000000..6565da078367
--- /dev/null
+++ b/src/pages/Search/SearchFiltersDatePage.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import {View} from 'react-native';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Text from '@src/components/Text';
+
+function SearchFiltersDatePage() {
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+
+ return (
+
+
+
+
+ {/* temporary placeholder, will be implemented in https://github.com/Expensify/App/issues/45026 */}
+ Advanced filters Date form
+
+
+
+ );
+}
+
+SearchFiltersDatePage.displayName = 'SearchFiltersDatePage';
+
+export default SearchFiltersDatePage;
diff --git a/src/pages/Search/SearchFiltersTypePage.tsx b/src/pages/Search/SearchFiltersTypePage.tsx
new file mode 100644
index 000000000000..e18b865f20ef
--- /dev/null
+++ b/src/pages/Search/SearchFiltersTypePage.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import {View} from 'react-native';
+import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
+import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import ScreenWrapper from '@components/ScreenWrapper';
+import useLocalize from '@hooks/useLocalize';
+import useThemeStyles from '@hooks/useThemeStyles';
+import Text from '@src/components/Text';
+
+function SearchFiltersTypePage() {
+ const styles = useThemeStyles();
+ const {translate} = useLocalize();
+
+ return (
+
+
+
+
+ {/* temporary placeholder, will be implemented in https://github.com/Expensify/App/issues/45026 */}
+ Advanced filters Type form
+
+
+
+ );
+}
+
+SearchFiltersTypePage.displayName = 'SearchFiltersTypePage';
+
+export default SearchFiltersTypePage;
diff --git a/src/pages/Search/SearchPageBottomTab.tsx b/src/pages/Search/SearchPageBottomTab.tsx
index 9ae6423a6cc1..965917bc5ebe 100644
--- a/src/pages/Search/SearchPageBottomTab.tsx
+++ b/src/pages/Search/SearchPageBottomTab.tsx
@@ -4,7 +4,7 @@ import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import ScreenWrapper from '@components/ScreenWrapper';
import Search from '@components/Search';
-import useActiveBottomTabRoute from '@hooks/useActiveBottomTabRoute';
+import useActiveCentralPaneRoute from '@hooks/useActiveCentralPaneRoute';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
@@ -28,7 +28,7 @@ const defaultSearchProps = {
function SearchPageBottomTab() {
const {translate} = useLocalize();
const {isSmallScreenWidth} = useWindowDimensions();
- const activeBottomTabRoute = useActiveBottomTabRoute();
+ const activeCentralPaneRoute = useActiveCentralPaneRoute();
const styles = useThemeStyles();
const [isMobileSelectionModeActive, setIsMobileSelectionModeActive] = useState(false);
@@ -38,11 +38,11 @@ function SearchPageBottomTab() {
sortBy,
sortOrder,
} = useMemo(() => {
- if (activeBottomTabRoute?.name !== SCREENS.SEARCH.CENTRAL_PANE || !activeBottomTabRoute.params) {
+ if (activeCentralPaneRoute?.name !== SCREENS.SEARCH.CENTRAL_PANE || !activeCentralPaneRoute.params) {
return defaultSearchProps;
}
- return {...defaultSearchProps, ...activeBottomTabRoute.params} as SearchPageProps['route']['params'];
- }, [activeBottomTabRoute]);
+ return {...defaultSearchProps, ...activeCentralPaneRoute.params} as SearchPageProps['route']['params'];
+ }, [activeCentralPaneRoute]);
const query = rawQuery as SearchQuery;
diff --git a/src/pages/ShareCodePage.tsx b/src/pages/ShareCodePage.tsx
index 9dfb5ae07a47..e11e99a6e852 100644
--- a/src/pages/ShareCodePage.tsx
+++ b/src/pages/ShareCodePage.tsx
@@ -2,6 +2,7 @@ import React, {useMemo, useRef} from 'react';
import {View} from 'react-native';
import type {ImageSourcePropType} from 'react-native';
import type {OnyxEntry} from 'react-native-onyx';
+import type {SvgProps} from 'react-native-svg';
import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png';
import ContextMenuItem from '@components/ContextMenuItem';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
@@ -14,6 +15,7 @@ import ScrollView from '@components/ScrollView';
import useCurrentUserPersonalDetails from '@hooks/useCurrentUserPersonalDetails';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
+import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import Clipboard from '@libs/Clipboard';
import Navigation from '@libs/Navigation/Navigation';
@@ -22,17 +24,38 @@ import * as Url from '@libs/Url';
import * as UserUtils from '@libs/UserUtils';
import CONST from '@src/CONST';
import ROUTES from '@src/ROUTES';
-import type {Report} from '@src/types/onyx';
+import type {Policy, Report} from '@src/types/onyx';
type ShareCodePageOnyxProps = {
/** The report currently being looked at */
report?: OnyxEntry;
+
+ /** The policy for the report currently being looked at */
+ policy?: OnyxEntry;
};
type ShareCodePageProps = ShareCodePageOnyxProps;
-function ShareCodePage({report}: ShareCodePageProps) {
+/**
+ * When sharing a policy (workspace) only return user avatar that is user defined. Default ws avatars have separate logic.
+ * In any other case default to expensify logo
+ */
+
+function getLogoForWorkspace(report: OnyxEntry, policy?: OnyxEntry): ImageSourcePropType | undefined {
+ if (!policy || !policy.id || report?.type !== 'chat') {
+ return expensifyLogo;
+ }
+
+ if (!policy.avatarURL) {
+ return undefined;
+ }
+
+ return policy.avatarURL as ImageSourcePropType;
+}
+
+function ShareCodePage({report, policy}: ShareCodePageProps) {
const themeStyles = useThemeStyles();
+ const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const {environmentURL} = useEnvironment();
const qrCodeRef = useRef(null);
@@ -64,6 +87,21 @@ function ShareCodePage({report}: ShareCodePageProps) {
? `${urlWithTrailingSlash}${ROUTES.REPORT_WITH_ID.getRoute(report.reportID)}`
: `${urlWithTrailingSlash}${ROUTES.PROFILE.getRoute(currentUserPersonalDetails.accountID ?? '-1')}`;
+ const logo = isReport ? getLogoForWorkspace(report, policy) : (UserUtils.getAvatarUrl(currentUserPersonalDetails?.avatar, currentUserPersonalDetails?.accountID) as ImageSourcePropType);
+
+ // Default logos (avatars) are SVG and they require some special logic to display correctly
+ let svgLogo: React.FC | undefined;
+ let logoBackgroundColor: string | undefined;
+ let svgLogoFillColor: string | undefined;
+
+ if (!logo && policy && !policy.avatarURL) {
+ svgLogo = ReportUtils.getDefaultWorkspaceAvatar(policy.name) || Expensicons.FallbackAvatar;
+
+ const defaultWorkspaceAvatarColors = StyleUtils.getDefaultWorkspaceAvatarColor(policy.id ?? '');
+ logoBackgroundColor = defaultWorkspaceAvatarColors.backgroundColor?.toString();
+ svgLogoFillColor = defaultWorkspaceAvatarColors.fill;
+ }
+
return (
diff --git a/src/pages/home/ReportScreen.tsx b/src/pages/home/ReportScreen.tsx
index 49897928ffe9..ca49eabb738e 100644
--- a/src/pages/home/ReportScreen.tsx
+++ b/src/pages/home/ReportScreen.tsx
@@ -5,8 +5,8 @@ import lodashIsEqual from 'lodash/isEqual';
import React, {memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState} from 'react';
import type {FlatList, ViewStyle} from 'react-native';
import {InteractionManager, View} from 'react-native';
-import type {OnyxEntry} from 'react-native-onyx';
-import {useOnyx} from 'react-native-onyx';
+import type {OnyxCollection, OnyxEntry} from 'react-native-onyx';
+import {useOnyx, withOnyx} from 'react-native-onyx';
import Banner from '@components/Banner';
import BlockingView from '@components/BlockingViews/BlockingView';
import FullPageNotFoundView from '@components/BlockingViews/FullPageNotFoundView';
@@ -59,9 +59,28 @@ import ReportFooter from './report/ReportFooter';
import type {ActionListContextType, ReactionListRef, ScrollPosition} from './ReportScreenContext';
import {ActionListContext, ReactionListContext} from './ReportScreenContext';
+type ReportScreenOnyxProps = {
+ /** Tells us if the sidebar has rendered */
+ isSidebarLoaded: OnyxEntry;
+
+ /** Beta features list */
+ betas: OnyxEntry;
+
+ /** The policies which the user has access to */
+ policies: OnyxCollection;
+
+ /** The report metadata loading states */
+ reportMetadata: OnyxEntry;
+};
+
+type OnyxHOCProps = {
+ /** Onyx function that marks the component ready for hydration */
+ markReadyForHydration?: () => void;
+};
+
type ReportScreenNavigationProps = StackScreenProps;
-type ReportScreenProps = CurrentReportIDContextValue & ReportScreenNavigationProps;
+type ReportScreenProps = OnyxHOCProps & CurrentReportIDContextValue & ReportScreenOnyxProps & ReportScreenNavigationProps;
/** Get the currently viewed report ID as number */
function getReportID(route: ReportScreenNavigationProps['route']): string {
@@ -91,7 +110,22 @@ function getParentReportAction(parentReportActions: OnyxEntry {
// Don't update if there is a reportID in the params already
@@ -149,6 +172,8 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
return;
}
+ const lastAccessedReportID = ReportUtils.findLastAccessedReport(!canUseDefaultRooms, !!route.params.openOnAdminRoom, activeWorkspaceID)?.reportID;
+
// It's possible that reports aren't fully loaded yet
// in that case the reportID is undefined
if (!lastAccessedReportID) {
@@ -157,7 +182,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
Log.info(`[ReportScreen] no reportID found in params, setting it to lastAccessedReportID: ${lastAccessedReportID}`);
navigation.setParams({reportID: lastAccessedReportID});
- }, [lastAccessedReportID, activeWorkspaceID, canUseDefaultRooms, navigation, route]);
+ }, [activeWorkspaceID, canUseDefaultRooms, navigation, route, finishedLoadingApp]);
/**
* Create a lightweight Report so as to keep the re-rendering as light as possible by
@@ -203,6 +228,8 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
visibility: reportOnyx?.visibility,
oldPolicyName: reportOnyx?.oldPolicyName,
policyName: reportOnyx?.policyName,
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ private_isArchived: reportOnyx?.private_isArchived,
isOptimisticReport: reportOnyx?.isOptimisticReport,
lastMentionedTime: reportOnyx?.lastMentionedTime,
avatarUrl: reportOnyx?.avatarUrl,
@@ -244,6 +271,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
reportOnyx?.visibility,
reportOnyx?.oldPolicyName,
reportOnyx?.policyName,
+ reportOnyx?.private_isArchived,
reportOnyx?.isOptimisticReport,
reportOnyx?.lastMentionedTime,
reportOnyx?.avatarUrl,
@@ -534,7 +562,8 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
(!prevUserLeavingStatus && !!userLeavingStatus) ||
didReportClose ||
isRemovalExpectedForReportType ||
- isClosedTopLevelPolicyRoom
+ isClosedTopLevelPolicyRoom ||
+ (prevIsDeletedParentAction && !isDeletedParentAction)
) {
// Early return if the report we're passing isn't in a focused state. We only want to navigate to Concierge if the user leaves the room from another device or gets removed from the room while the report is in a focused state.
// Prevent auto navigation for report in RHP
@@ -584,6 +613,8 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
prevReport,
reportIDFromRoute,
isFocused,
+ isDeletedParentAction,
+ prevIsDeletedParentAction,
]);
useEffect(() => {
@@ -614,6 +645,15 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
};
}, [report, didSubscribeToReportLeavingEvents, reportIDFromRoute]);
+ const onListLayout = useCallback(() => {
+ if (!markReadyForHydration) {
+ return;
+ }
+
+ markReadyForHydration();
+ // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
+ }, []);
+
const actionListValue = useMemo((): ActionListContextType => ({flatListRef, scrollPosition, setScrollPosition}), [flatListRef, scrollPosition, setScrollPosition]);
// This helps in tracking from the moment 'route' triggers useMemo until isLoadingInitialReportActions becomes true. It prevents blinking when loading reportActions from cache.
@@ -725,6 +765,7 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
{shouldShowReportActionList && (
@@ -771,4 +812,42 @@ function ReportScreen({route, currentReportID = '', navigation}: ReportScreenPro
}
ReportScreen.displayName = 'ReportScreen';
-export default withCurrentReportID(memo(ReportScreen, (prevProps, nextProps) => prevProps.currentReportID === nextProps.currentReportID && lodashIsEqual(prevProps.route, nextProps.route)));
+
+export default withCurrentReportID(
+ withOnyx(
+ {
+ isSidebarLoaded: {
+ key: ONYXKEYS.IS_SIDEBAR_LOADED,
+ },
+ reportMetadata: {
+ key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT_METADATA}${getReportID(route)}`,
+ initialValue: {
+ isLoadingInitialReportActions: true,
+ isLoadingOlderReportActions: false,
+ hasLoadingOlderReportActionsError: false,
+ isLoadingNewerReportActions: false,
+ hasLoadingNewerReportActionsError: false,
+ },
+ },
+ betas: {
+ key: ONYXKEYS.BETAS,
+ },
+ policies: {
+ key: ONYXKEYS.COLLECTION.POLICY,
+ allowStaleData: true,
+ },
+ },
+ true,
+ )(
+ memo(
+ ReportScreen,
+ (prevProps, nextProps) =>
+ prevProps.isSidebarLoaded === nextProps.isSidebarLoaded &&
+ lodashIsEqual(prevProps.reportMetadata, nextProps.reportMetadata) &&
+ lodashIsEqual(prevProps.betas, nextProps.betas) &&
+ lodashIsEqual(prevProps.policies, nextProps.policies) &&
+ prevProps.currentReportID === nextProps.currentReportID &&
+ lodashIsEqual(prevProps.route, nextProps.route),
+ ),
+ ),
+);
diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx
index 8d5a544afd42..c6a4738331b7 100644
--- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx
+++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.tsx
@@ -222,6 +222,7 @@ function SuggestionEmoji(
preferredSkinToneIndex={preferredSkinTone}
isEmojiPickerLarge={!!isAutoSuggestionPickerLarge}
measureParentContainerAndReportCursor={measureParentContainerAndReportCursor}
+ resetSuggestions={resetSuggestions}
/>
);
}
diff --git a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx
index 86a05bad1994..740159694691 100644
--- a/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx
+++ b/src/pages/home/report/ReportActionCompose/SuggestionMention.tsx
@@ -435,6 +435,7 @@ function SuggestionMention(
onSelect={insertSelectedMention}
isMentionPickerLarge={!!isAutoSuggestionPickerLarge}
measureParentContainerAndReportCursor={measureParentContainerAndReportCursor}
+ resetSuggestions={resetSuggestions}
/>
);
}
diff --git a/src/pages/home/report/ReportActionItem.tsx b/src/pages/home/report/ReportActionItem.tsx
index 10ec9bb72dff..b5ee3607f359 100644
--- a/src/pages/home/report/ReportActionItem.tsx
+++ b/src/pages/home/report/ReportActionItem.tsx
@@ -408,7 +408,7 @@ function ReportActionItem({
text: 'subscription.cardSection.addCardButton',
key: `${action.reportActionID}-actionableAddPaymentCard-submit`,
onPress: () => {
- Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION);
+ Navigation.navigate(ROUTES.SETTINGS_SUBSCRIPTION_ADD_PAYMENT_CARD);
},
isMediumSized: true,
isPrimary: true,
diff --git a/src/pages/home/report/ReportActionItemContentCreated.tsx b/src/pages/home/report/ReportActionItemContentCreated.tsx
index c34cf3991900..776ea8aeea02 100644
--- a/src/pages/home/report/ReportActionItemContentCreated.tsx
+++ b/src/pages/home/report/ReportActionItemContentCreated.tsx
@@ -75,7 +75,7 @@ function ReportActionItemContentCreated({contextValue, parentReportAction, trans
if (ReportActionsUtils.isTransactionThread(parentReportAction)) {
const isReversedTransaction = ReportActionsUtils.isReversedTransaction(parentReportAction);
- if (ReportActionsUtils.isDeletedParentAction(parentReportAction) || isReversedTransaction) {
+ if (ReportActionsUtils.isMessageDeleted(parentReportAction) || isReversedTransaction) {
let message: TranslationPaths;
if (isReversedTransaction) {
diff --git a/src/pages/home/report/ReportActionItemMessageEdit.tsx b/src/pages/home/report/ReportActionItemMessageEdit.tsx
index b34cd68730f0..726679351b79 100644
--- a/src/pages/home/report/ReportActionItemMessageEdit.tsx
+++ b/src/pages/home/report/ReportActionItemMessageEdit.tsx
@@ -194,7 +194,7 @@ function ReportActionItemMessageEdit(
}
// Show the main composer when the focused message is deleted from another client
- // to prevent the main composer stays hidden until we swtich to another chat.
+ // to prevent the main composer stays hidden until we switch to another chat.
setShouldShowComposeInputKeyboardAware(true);
};
},
@@ -354,7 +354,7 @@ function ReportActionItemMessageEdit(
const keyEvent = e as KeyboardEvent;
const isSuggestionsMenuVisible = suggestionsRef.current?.getIsSuggestionsMenuVisible();
- if (isSuggestionsMenuVisible && keyEvent.key === CONST.KEYBOARD_SHORTCUTS.ENTER.shortcutKey) {
+ if (isSuggestionsMenuVisible) {
suggestionsRef.current?.triggerHotkeyActions(keyEvent);
return;
}
@@ -374,16 +374,12 @@ function ReportActionItemMessageEdit(
[deleteDraft, hideSuggestionMenu, isKeyboardShown, isSmallScreenWidth, publishDraft],
);
- const measureContainer = useCallback(
- (callback: MeasureInWindowOnSuccessCallback) => {
- if (!containerRef.current) {
- return;
- }
- containerRef.current.measureInWindow(callback);
- },
- // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
- [isFocused],
- );
+ const measureContainer = useCallback((callback: MeasureInWindowOnSuccessCallback) => {
+ if (!containerRef.current) {
+ return;
+ }
+ containerRef.current.measureInWindow(callback);
+ }, []);
const measureParentContainerAndReportCursor = useCallback(
(callback: MeasureParentContainerAndCursorCallback) => {
@@ -408,8 +404,7 @@ function ReportActionItemMessageEdit(
// eslint-disable-next-line react-compiler/react-compiler
tag.value = findNodeHandle(textInputRef.current) ?? -1;
- // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
- }, []);
+ }, [tag]);
useFocusedInputHandler(
{
onSelectionChange: (event) => {
diff --git a/src/pages/home/report/ReportActionsList.tsx b/src/pages/home/report/ReportActionsList.tsx
index 8b629c8d4b6f..b8ff8b690d8e 100644
--- a/src/pages/home/report/ReportActionsList.tsx
+++ b/src/pages/home/report/ReportActionsList.tsx
@@ -271,9 +271,7 @@ function ReportActionsList({
const isFromNotification = route?.params?.referrer === CONST.REFERRER.NOTIFICATION;
if ((Visibility.isVisible() || isFromNotification) && scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD) {
Report.readNewestAction(report.reportID);
- if (isFromNotification) {
- Navigation.setParams({referrer: undefined});
- }
+ Navigation.setParams({referrer: undefined});
} else {
readActionSkipped.current = true;
}
@@ -688,7 +686,7 @@ function ReportActionsList({
isActive={(isFloatingMessageCounterVisible && !!currentUnreadMarker) || canScrollToNewerComments}
onClick={scrollToBottomAndMarkReportAsRead}
/>
-
+ ;
+};
-function ReportDetailsShareCodePage({report}: ReportDetailsShareCodePageProps) {
+type ReportDetailsShareCodePageProps = ReportDetailsShareCodePageOnyxProps & WithReportOrNotFoundProps;
+
+function ReportDetailsShareCodePage({report, policy}: ReportDetailsShareCodePageProps) {
if (ReportUtils.isSelfDM(report)) {
return ;
}
- return ;
+ return (
+
+ );
}
-export default withReportOrNotFound()(ReportDetailsShareCodePage);
+export default withReportOrNotFound()(
+ withOnyx({
+ policy: {
+ key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY}${report?.policyID}`,
+ },
+ })(ReportDetailsShareCodePage),
+);
diff --git a/src/pages/home/report/ReportFooter.tsx b/src/pages/home/report/ReportFooter.tsx
index 8c13b0f8696c..a02b5ca3af44 100644
--- a/src/pages/home/report/ReportFooter.tsx
+++ b/src/pages/home/report/ReportFooter.tsx
@@ -103,7 +103,7 @@ function ReportFooter({
// If a user just signed in and is viewing a public report, optimistically show the composer while loading the report, since they will have write access when the response comes back.
const shouldShowComposerOptimistically = !isAnonymousUser && ReportUtils.isPublicRoom(report) && !!reportMetadata?.isLoadingInitialReportActions;
- const shouldHideComposer = (!ReportUtils.canUserPerformWriteAction(report, reportNameValuePairs) && !shouldShowComposerOptimistically) || isBlockedFromChat;
+ const shouldHideComposer = (!ReportUtils.canUserPerformWriteAction(report) && !shouldShowComposerOptimistically) || isBlockedFromChat;
const canWriteInReport = ReportUtils.canWriteInReport(report);
const isSystemChat = ReportUtils.isSystemChat(report);
const isAdminsOnlyPostingRoom = ReportUtils.isAdminsOnlyPostingRoom(report);
diff --git a/src/pages/iou/SplitBillDetailsPage.tsx b/src/pages/iou/SplitBillDetailsPage.tsx
index d31c67624bd2..24bac1a0dde8 100644
--- a/src/pages/iou/SplitBillDetailsPage.tsx
+++ b/src/pages/iou/SplitBillDetailsPage.tsx
@@ -146,6 +146,9 @@ function SplitBillDetailsPage({personalDetails, report, route, reportActions, tr
isPolicyExpenseChat={ReportUtils.isPolicyExpenseChat(report)}
policyID={ReportUtils.isPolicyExpenseChat(report) ? report?.policyID : undefined}
action={isEditingSplitBill ? CONST.IOU.ACTION.EDIT : CONST.IOU.ACTION.CREATE}
+ onToggleBillable={(billable) => {
+ IOU.setDraftSplitTransaction(transaction?.transactionID ?? '-1', {billable});
+ }}
/>
)}
diff --git a/src/pages/iou/request/step/IOURequestStepDistance.tsx b/src/pages/iou/request/step/IOURequestStepDistance.tsx
index 5d3b701424d5..66f7ec28fa01 100644
--- a/src/pages/iou/request/step/IOURequestStepDistance.tsx
+++ b/src/pages/iou/request/step/IOURequestStepDistance.tsx
@@ -94,13 +94,12 @@ function IOURequestStepDistance({
const isLoadingRoute = transaction?.comment?.isLoading ?? false;
const isLoading = transaction?.isLoading ?? false;
const hasRouteError = !!transaction?.errorFields?.route;
- const hasRoute = TransactionUtils.hasRoute(transaction, true);
+ const hasRoute = TransactionUtils.hasRoute(transaction);
const validatedWaypoints = TransactionUtils.getValidWaypoints(waypoints);
const previousValidatedWaypoints = usePrevious(validatedWaypoints);
const haveValidatedWaypointsChanged = !isEqual(previousValidatedWaypoints, validatedWaypoints);
const isRouteAbsentWithoutErrors = !hasRoute && !hasRouteError;
- const isEmptyCoordinates = !transaction?.routes?.route0?.geometry?.coordinates?.length;
- const shouldFetchRoute = (isEmptyCoordinates || isRouteAbsentWithoutErrors || haveValidatedWaypointsChanged) && !isLoadingRoute && Object.keys(validatedWaypoints).length > 1;
+ const shouldFetchRoute = (isRouteAbsentWithoutErrors || haveValidatedWaypointsChanged) && !isLoadingRoute && Object.keys(validatedWaypoints).length > 1;
const [shouldShowAtLeastTwoDifferentWaypointsError, setShouldShowAtLeastTwoDifferentWaypointsError] = useState(false);
const isWaypointEmpty = (waypoint?: Waypoint) => {
if (!waypoint) {
@@ -119,6 +118,8 @@ function IOURequestStepDistance({
const isEditing = action === CONST.IOU.ACTION.EDIT;
const transactionWasSaved = useRef(false);
const isCreatingNewRequest = !(backTo || isEditing);
+ const [recentWaypoints, {status: recentWaypointsStatus}] = useOnyx(ONYXKEYS.NVP_RECENT_WAYPOINTS);
+ const iouRequestType = TransactionUtils.getRequestType(transaction);
// For quick button actions, we'll skip the confirmation page unless the report is archived or this is a workspace
// request and the workspace requires a category or a tag
@@ -142,6 +143,16 @@ function IOURequestStepDistance({
}
}
+ useEffect(() => {
+ if (iouRequestType !== CONST.IOU.REQUEST_TYPE.DISTANCE || isOffline || recentWaypointsStatus === 'loading' || recentWaypoints !== undefined) {
+ return;
+ }
+
+ // Only load the recent waypoints if they have been read from Onyx as undefined
+ // If the account doesn't have recent waypoints they will be returned as an empty array
+ TransactionAction.openDraftDistanceExpense();
+ }, [iouRequestType, recentWaypointsStatus, recentWaypoints, isOffline]);
+
useEffect(() => {
MapboxToken.init();
return MapboxToken.stop;
@@ -261,7 +272,7 @@ function IOURequestStepDistance({
category: '',
tag: '',
billable: false,
- iouRequestType: CONST.IOU.REQUEST_TYPE.DISTANCE,
+ iouRequestType,
existingSplitChatReportID: report?.reportID,
});
return;
@@ -333,6 +344,7 @@ function IOURequestStepDistance({
navigateToParticipantPage,
navigateToConfirmationPage,
policy,
+ iouRequestType,
reportNameValuePairs,
]);
diff --git a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx
index fca23d1e1cb9..f0169b410257 100644
--- a/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx
+++ b/src/pages/settings/AboutPage/ShareLogList/BaseShareLogList.tsx
@@ -27,30 +27,52 @@ function BaseShareLogList({onAttachLogToReport}: BaseShareLogListProps) {
const [isSearchingForReports] = useOnyx(ONYXKEYS.IS_SEARCHING_FOR_REPORTS, {initWithStoredValues: false});
const {options, areOptionsInitialized} = useOptionsList();
- const searchOptions = useMemo(() => {
+ const defaultOptions = useMemo(() => {
if (!areOptionsInitialized) {
return {
recentReports: [],
personalDetails: [],
- userToInvite: undefined,
+ userToInvite: null,
+ currentUserOption: null,
+ categoryOptions: [],
+ tagOptions: [],
+ taxRatesOptions: [],
headerMessage: '',
};
}
- const {
- recentReports: localRecentReports,
- personalDetails: localPersonalDetails,
- userToInvite: localUserToInvite,
- } = OptionsListUtils.getShareLogOptions(options, debouncedSearchValue.trim(), betas ?? []);
+ const shareLogOptions = OptionsListUtils.getShareLogOptions(options, '', betas ?? []);
- const header = OptionsListUtils.getHeaderMessage((localRecentReports?.length || 0) + (localPersonalDetails?.length || 0) !== 0, !!localUserToInvite, debouncedSearchValue);
+ const header = OptionsListUtils.getHeaderMessage(
+ (shareLogOptions.recentReports.length || 0) + (shareLogOptions.personalDetails.length || 0) !== 0,
+ !!shareLogOptions.userToInvite,
+ '',
+ );
return {
- recentReports: localRecentReports,
- personalDetails: localPersonalDetails,
- userToInvite: localUserToInvite,
+ ...shareLogOptions,
headerMessage: header,
};
- }, [areOptionsInitialized, options, debouncedSearchValue, betas]);
+ }, [areOptionsInitialized, options, betas]);
+
+ const searchOptions = useMemo(() => {
+ if (debouncedSearchValue.trim() === '') {
+ return defaultOptions;
+ }
+
+ const filteredOptions = OptionsListUtils.filterOptions(defaultOptions, debouncedSearchValue, {
+ includeChatRoomsByParticipants: true,
+ preferChatroomsOverThreads: true,
+ sortByReportTypeInSearch: true,
+ });
+
+ const headerMessage = OptionsListUtils.getHeaderMessage(
+ (filteredOptions.recentReports?.length || 0) + (filteredOptions.personalDetails?.length || 0) !== 0,
+ !!filteredOptions.userToInvite,
+ debouncedSearchValue.trim(),
+ );
+
+ return {...filteredOptions, headerMessage};
+ }, [debouncedSearchValue, defaultOptions]);
const sections = useMemo(() => {
const sectionsList = [];
diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx
index d8051a5f7ed5..e11da8bf49fc 100755
--- a/src/pages/settings/InitialSettingsPage.tsx
+++ b/src/pages/settings/InitialSettingsPage.tsx
@@ -20,7 +20,7 @@ import Text from '@components/Text';
import Tooltip from '@components/Tooltip';
import type {WithCurrentUserPersonalDetailsProps} from '@components/withCurrentUserPersonalDetails';
import withCurrentUserPersonalDetails from '@components/withCurrentUserPersonalDetails';
-import useActiveBottomTabRoute from '@hooks/useActiveBottomTabRoute';
+import useActiveCentralPaneRoute from '@hooks/useActiveCentralPaneRoute';
import useLocalize from '@hooks/useLocalize';
import useNetwork from '@hooks/useNetwork';
import useSingleExecution from '@hooks/useSingleExecution';
@@ -104,7 +104,7 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa
const waitForNavigate = useWaitForNavigation();
const popoverAnchor = useRef(null);
const {translate, formatPhoneNumber} = useLocalize();
- const activeBottomTabRoute = useActiveBottomTabRoute();
+ const activeCentralPaneRoute = useActiveCentralPaneRoute();
const emojiCode = currentUserPersonalDetails?.status?.emojiCode ?? '';
const [privateSubscription] = useOnyx(ONYXKEYS.NVP_PRIVATE_SUBSCRIPTION);
@@ -330,9 +330,9 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa
shouldBlockSelection={!!item.link}
onSecondaryInteraction={item.link ? (event) => openPopover(item.link, event) : undefined}
focused={
- !!activeBottomTabRoute &&
+ !!activeCentralPaneRoute &&
!!item.routeName &&
- !!(activeBottomTabRoute.name.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', ''))
+ !!(activeCentralPaneRoute.name.toLowerCase().replaceAll('_', '') === item.routeName.toLowerCase().replaceAll('/', ''))
}
isPaneMenu
iconRight={item.iconRight}
@@ -353,7 +353,7 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa
userWallet?.currentBalance,
isExecuting,
singleExecution,
- activeBottomTabRoute,
+ activeCentralPaneRoute,
waitForNavigate,
],
);
diff --git a/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.tsx b/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.tsx
index 9604a7d1627f..9681b372483b 100644
--- a/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.tsx
+++ b/src/pages/settings/Security/TwoFactorAuth/Steps/SuccessStep.tsx
@@ -1,26 +1,18 @@
import React from 'react';
import ConfirmationPage from '@components/ConfirmationPage';
import LottieAnimations from '@components/LottieAnimations';
-import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
+import type {BackToParams} from '@libs/Navigation/types';
import Navigation from '@navigation/Navigation';
import StepWrapper from '@pages/settings/Security/TwoFactorAuth/StepWrapper/StepWrapper';
import useTwoFactorAuthContext from '@pages/settings/Security/TwoFactorAuth/TwoFactorAuthContext/useTwoFactorAuth';
-import * as Link from '@userActions/Link';
import * as TwoFactorAuthActions from '@userActions/TwoFactorAuthActions';
import CONST from '@src/CONST';
-import type {Route} from '@src/ROUTES';
-type SuccessStepParams = {
- backTo?: Route;
- forwardTo?: string;
-};
-
-function SuccessStep({backTo, forwardTo}: SuccessStepParams) {
+function SuccessStep({backTo}: BackToParams) {
const {setStep} = useTwoFactorAuthContext();
const {translate} = useLocalize();
- const {environmentURL} = useEnvironment();
return (
diff --git a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx
index 76b1e7cfb0f7..5ee440ef257a 100644
--- a/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx
+++ b/src/pages/settings/Security/TwoFactorAuth/TwoFactorAuthSteps.tsx
@@ -23,8 +23,6 @@ type TwoFactorAuthStepProps = BaseTwoFactorAuthFormOnyxProps;
function TwoFactorAuthSteps({account}: TwoFactorAuthStepProps) {
const route = useRoute>();
const backTo = route.params?.backTo ?? '';
- const forwardTo = route.params?.forwardTo ?? '';
-
const currentStep = useMemo(() => {
if (account?.twoFactorAuthStep) {
return account.twoFactorAuthStep;
@@ -52,12 +50,7 @@ function TwoFactorAuthSteps({account}: TwoFactorAuthStepProps) {
case CONST.TWO_FACTOR_AUTH_STEPS.VERIFY:
return ;
case CONST.TWO_FACTOR_AUTH_STEPS.SUCCESS:
- return (
-
- );
+ return ;
case CONST.TWO_FACTOR_AUTH_STEPS.ENABLED:
return ;
case CONST.TWO_FACTOR_AUTH_STEPS.DISABLED:
diff --git a/src/pages/workspace/WorkspaceInitialPage.tsx b/src/pages/workspace/WorkspaceInitialPage.tsx
index d622be617f22..267a3ac38850 100644
--- a/src/pages/workspace/WorkspaceInitialPage.tsx
+++ b/src/pages/workspace/WorkspaceInitialPage.tsx
@@ -284,6 +284,15 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAcc
});
}
+ if (featureStates?.[CONST.POLICY.MORE_FEATURES.ARE_REPORT_FIELDS_ENABLED]) {
+ protectedCollectPolicyMenuItems.push({
+ translationKey: 'workspace.common.reportFields',
+ icon: Expensicons.Pencil,
+ action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELDS.getRoute(policyID)))),
+ routeName: SCREENS.WORKSPACE.REPORT_FIELDS,
+ });
+ }
+
if (featureStates?.[CONST.POLICY.MORE_FEATURES.ARE_CONNECTIONS_ENABLED]) {
protectedCollectPolicyMenuItems.push({
translationKey: 'workspace.common.accounting',
@@ -295,15 +304,6 @@ function WorkspaceInitialPage({policyDraft, policy: policyProp, reimbursementAcc
});
}
- if (featureStates?.[CONST.POLICY.MORE_FEATURES.ARE_REPORT_FIELDS_ENABLED]) {
- protectedCollectPolicyMenuItems.push({
- translationKey: 'workspace.common.reportFields',
- icon: Expensicons.Pencil,
- action: singleExecution(waitForNavigate(() => Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELDS.getRoute(policyID)))),
- routeName: SCREENS.WORKSPACE.REPORT_FIELDS,
- });
- }
-
protectedCollectPolicyMenuItems.push({
translationKey: 'workspace.common.moreFeatures',
icon: Expensicons.Gear,
diff --git a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
index 2c966eebeea4..46d897bd0a0f 100644
--- a/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
+++ b/src/pages/workspace/WorkspaceMoreFeaturesPage.tsx
@@ -17,6 +17,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions';
import * as ErrorUtils from '@libs/ErrorUtils';
import Navigation from '@libs/Navigation/Navigation';
import type {FullScreenNavigatorParamList} from '@libs/Navigation/types';
+import {isControlPolicy} from '@libs/PolicyUtils';
import * as Category from '@userActions/Policy/Category';
import * as DistanceRate from '@userActions/Policy/DistanceRate';
import * as Policy from '@userActions/Policy/Policy';
@@ -204,6 +205,13 @@ function WorkspaceMoreFeaturesPage({policy, route}: WorkspaceMoreFeaturesPagePro
return;
}
if (isEnabled) {
+ if (!isControlPolicy(policy)) {
+ Navigation.navigate(
+ ROUTES.WORKSPACE_UPGRADE.getRoute(policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.reportFields.alias, ROUTES.WORKSPACE_MORE_FEATURES.getRoute(policyID)),
+ );
+ return;
+ }
+
Policy.enablePolicyReportFields(policyID, true);
return;
}
diff --git a/src/pages/workspace/WorkspaceProfileSharePage.tsx b/src/pages/workspace/WorkspaceProfileSharePage.tsx
index 1f613d707edc..7e996c761035 100644
--- a/src/pages/workspace/WorkspaceProfileSharePage.tsx
+++ b/src/pages/workspace/WorkspaceProfileSharePage.tsx
@@ -1,7 +1,6 @@
import React, {useMemo, useRef} from 'react';
import {View} from 'react-native';
import type {ImageSourcePropType} from 'react-native';
-import expensifyLogo from '@assets/images/expensify-logo-round-transparent.png';
import ContextMenuItem from '@components/ContextMenuItem';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
import * as Expensicons from '@components/Icon/Expensicons';
@@ -14,6 +13,7 @@ import Text from '@components/Text';
import TextLink from '@components/TextLink';
import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
+import useStyleUtils from '@hooks/useStyleUtils';
import useThemeStyles from '@hooks/useThemeStyles';
import useWindowDimensions from '@hooks/useWindowDimensions';
import Clipboard from '@libs/Clipboard';
@@ -28,6 +28,7 @@ import type {WithPolicyProps} from './withPolicy';
function WorkspaceProfileSharePage({policy}: WithPolicyProps) {
const themeStyles = useThemeStyles();
+ const StyleUtils = useStyleUtils();
const {translate} = useLocalize();
const {environmentURL} = useEnvironment();
const qrCodeRef = useRef(null);
@@ -35,11 +36,22 @@ function WorkspaceProfileSharePage({policy}: WithPolicyProps) {
const session = useSession();
const policyName = policy?.name ?? '';
- const id = policy?.id ?? '-1';
+ const policyID = policy?.id ?? '-1';
const adminEmail = session?.email ?? '';
const urlWithTrailingSlash = Url.addTrailingForwardSlash(environmentURL);
- const url = `${urlWithTrailingSlash}${ROUTES.WORKSPACE_JOIN_USER.getRoute(id, adminEmail)}`;
+ const url = `${urlWithTrailingSlash}${ROUTES.WORKSPACE_JOIN_USER.getRoute(policyID, adminEmail)}`;
+
+ const hasAvatar = !!policy?.avatarURL;
+ const logo = hasAvatar ? (policy?.avatarURL as ImageSourcePropType) : undefined;
+
+ const defaultWorkspaceAvatar = ReportUtils.getDefaultWorkspaceAvatar(policyName) || Expensicons.FallbackAvatar;
+ const defaultWorkspaceAvatarColors = StyleUtils.getDefaultWorkspaceAvatarColor(policyID);
+
+ const svgLogo = !hasAvatar ? defaultWorkspaceAvatar : undefined;
+ const logoBackgroundColor = !hasAvatar ? defaultWorkspaceAvatarColors.backgroundColor?.toString() : undefined;
+ const svgLogoFillColor = !hasAvatar ? defaultWorkspaceAvatarColors.fill : undefined;
+
const adminRoom = useMemo(() => {
if (!policy?.id) {
return undefined;
@@ -49,7 +61,7 @@ function WorkspaceProfileSharePage({policy}: WithPolicyProps) {
return (
- {/*
+ {/*
Right now QR code download button is not shown anymore
This is a temporary measure because right now it's broken because of the Fabric update.
We need to wait for react-native v0.74 to be released so react-native-view-shot gets fixed.
-
+
Please see https://github.com/Expensify/App/issues/40110 to see if it can be re-enabled.
*/}
-
),
},
- ...(isEmptyObject(integrationSpecificMenuItems) || shouldShowSynchronizationError ? [] : [integrationSpecificMenuItems]),
+ ...(isEmptyObject(integrationSpecificMenuItems) || shouldShowSynchronizationError || isEmptyObject(policy?.connections) ? [] : [integrationSpecificMenuItems]),
...(isEmptyObject(policy?.connections) || shouldShowSynchronizationError
? []
: [
diff --git a/src/pages/workspace/accounting/reconciliation/CardReconciliationPage.tsx b/src/pages/workspace/accounting/reconciliation/CardReconciliationPage.tsx
index 27f31f587944..f6304b7e439a 100644
--- a/src/pages/workspace/accounting/reconciliation/CardReconciliationPage.tsx
+++ b/src/pages/workspace/accounting/reconciliation/CardReconciliationPage.tsx
@@ -1,19 +1,64 @@
-import React from 'react';
+import type {StackScreenProps} from '@react-navigation/stack';
+import React, {useCallback} from 'react';
+import {useOnyx} from 'react-native-onyx';
import HeaderWithBackButton from '@components/HeaderWithBackButton';
+import MenuItemWithTopDescription from '@components/MenuItemWithTopDescription';
import ScreenWrapper from '@components/ScreenWrapper';
import ScrollView from '@components/ScrollView';
+import Text from '@components/Text';
+import TextLink from '@components/TextLink';
import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
+import Navigation from '@navigation/Navigation';
+import type {SettingsNavigatorParamList} from '@navigation/types';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import type {WithPolicyConnectionsProps} from '@pages/workspace/withPolicyConnections';
import withPolicyConnections from '@pages/workspace/withPolicyConnections';
+import ToggleSettingOptionRow from '@pages/workspace/workflows/ToggleSettingsOptionRow';
import CONST from '@src/CONST';
+import ONYXKEYS from '@src/ONYXKEYS';
+import ROUTES from '@src/ROUTES';
+import type SCREENS from '@src/SCREENS';
-function CardReconciliationPage({policy}: WithPolicyConnectionsProps) {
+type CardReconciliationPageProps = WithPolicyConnectionsProps & StackScreenProps;
+
+function CardReconciliationPage({policy, route}: CardReconciliationPageProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
+ const [reconciliationConnection] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_EXPENSIFY_CARD_CONTINUOUS_RECONCILIATION_CONNECTION}${policy?.id}`);
+ const [isContinuousReconciliationOn] = useOnyx(`${ONYXKEYS.COLLECTION.SHARED_NVP_EXPENSIFY_CARD_USE_CONTINUOUS_RECONCILIATION}${policy?.id}`);
+
const policyID = policy?.id ?? '-1';
+ const {connection} = route.params;
+ const autoSync = !!policy?.connections?.[connection]?.config?.autoSync.enabled;
+
+ // eslint-disable-next-line rulesdir/prefer-early-return
+ const toggleContinuousReconciliation = () => {
+ if (!isContinuousReconciliationOn) {
+ Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_RECONCILIATION_ACCOUNT_SETTINGS.getRoute(policyID, connection));
+ }
+ // TODO: add API call when it's supported https://github.com/Expensify/Expensify/issues/407834
+ };
+
+ const navigateToAdvancedSettings = useCallback(() => {
+ switch (connection) {
+ case CONST.POLICY.CONNECTIONS.NAME.QBO:
+ Navigation.navigate(ROUTES.WORKSPACE_ACCOUNTING_QUICKBOOKS_ONLINE_ADVANCED.getRoute(policyID));
+ break;
+ case CONST.POLICY.CONNECTIONS.NAME.XERO:
+ Navigation.navigate(ROUTES.POLICY_ACCOUNTING_XERO_ADVANCED.getRoute(policyID));
+ break;
+ case CONST.POLICY.CONNECTIONS.NAME.NETSUITE:
+ Navigation.navigate(ROUTES.POLICY_ACCOUNTING_NETSUITE_ADVANCED.getRoute(policyID));
+ break;
+ case CONST.POLICY.CONNECTIONS.NAME.SAGE_INTACCT:
+ Navigation.navigate(ROUTES.POLICY_ACCOUNTING_SAGE_INTACCT_ADVANCED.getRoute(policyID));
+ break;
+ default:
+ break;
+ }
+ }, [connection, policyID]);
return (
-
+
+
+ {!autoSync && (
+
+ {translate('workspace.accounting.enableContinuousReconciliation')}
+
+ {translate('workspace.accounting.autoSync').toLowerCase()}
+ {' '}
+ {translate('common.conjunctionFor')} {CONST.POLICY.CONNECTIONS.NAME_USER_FRIENDLY[connection]}
+
+ )}
+ {!!reconciliationConnection && (
+
+ )}
+
);
diff --git a/src/pages/workspace/card/issueNew/AssigneeStep.tsx b/src/pages/workspace/card/issueNew/AssigneeStep.tsx
index 23acb3d4a24a..042e93ae2fae 100644
--- a/src/pages/workspace/card/issueNew/AssigneeStep.tsx
+++ b/src/pages/workspace/card/issueNew/AssigneeStep.tsx
@@ -119,6 +119,12 @@ function AssigneeStep({policy}: AssigneeStepProps) {
];
}, [membersDetails, debouncedSearchTerm]);
+ const headerMessage = useMemo(() => {
+ const searchValue = debouncedSearchTerm.trim().toLowerCase();
+
+ return OptionsListUtils.getHeaderMessage(sections[0].data.length !== 0, false, searchValue);
+ }, [debouncedSearchTerm, sections]);
+
return (
diff --git a/src/pages/workspace/card/issueNew/LimitStep.tsx b/src/pages/workspace/card/issueNew/LimitStep.tsx
index cc65a987bd62..5f97db54ff21 100644
--- a/src/pages/workspace/card/issueNew/LimitStep.tsx
+++ b/src/pages/workspace/card/issueNew/LimitStep.tsx
@@ -81,6 +81,7 @@ function LimitStep() {
formID={ONYXKEYS.FORMS.ISSUE_NEW_EXPENSIFY_CARD_FORM}
// TODO: change the submitButtonText to 'common.confirm' when editing and navigate to ConfirmationStep
submitButtonText={translate('common.next')}
+ shouldHideFixErrorsAlert
onSubmit={submit}
style={[styles.flex1]}
submitButtonStyles={[styles.mh5, styles.mt0]}
diff --git a/src/pages/workspace/categories/CategorySettingsPage.tsx b/src/pages/workspace/categories/CategorySettingsPage.tsx
index 959347b621fb..2732a928b6a4 100644
--- a/src/pages/workspace/categories/CategorySettingsPage.tsx
+++ b/src/pages/workspace/categories/CategorySettingsPage.tsx
@@ -140,7 +140,13 @@ function CategorySettingsPage({route, policyCategories, navigation}: CategorySet
Navigation.navigate(ROUTES.WORKSPACE_CATEGORY_GL_CODE.getRoute(route.params.policyID, policyCategory.name))}
+ onPress={() => {
+ if (!isControlPolicy(policy)) {
+ Navigation.navigate(ROUTES.WORKSPACE_UPGRADE.getRoute(route.params.policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.glAndPayrollCodes.alias));
+ return;
+ }
+ Navigation.navigate(ROUTES.WORKSPACE_CATEGORY_GL_CODE.getRoute(route.params.policyID, policyCategory.name));
+ }}
shouldShowRightIcon
/>
@@ -148,7 +154,13 @@ function CategorySettingsPage({route, policyCategories, navigation}: CategorySet
Navigation.navigate(ROUTES.WORKSPACE_CATEGORY_PAYROLL_CODE.getRoute(route.params.policyID, policyCategory.name))}
+ onPress={() => {
+ if (!isControlPolicy(policy)) {
+ Navigation.navigate(ROUTES.WORKSPACE_UPGRADE.getRoute(route.params.policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.glAndPayrollCodes.alias));
+ return;
+ }
+ Navigation.navigate(ROUTES.WORKSPACE_CATEGORY_PAYROLL_CODE.getRoute(route.params.policyID, policyCategory.name));
+ }}
shouldShowRightIcon
disabled={shouldDisablePayrollCode}
/>
diff --git a/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx b/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx
index 4a02e701b058..783434bd8d96 100644
--- a/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx
+++ b/src/pages/workspace/reportFields/CreateReportFieldsPage.tsx
@@ -14,6 +14,7 @@ import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportField from '@libs/actions/Policy/ReportField';
import DateUtils from '@libs/DateUtils';
import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
import type {SettingsNavigatorParamList} from '@navigation/types';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import type {WithPolicyAndFullscreenLoadingProps} from '@pages/workspace/withPolicyAndFullscreenLoading';
@@ -97,6 +98,7 @@ function CreateReportFieldsPage({
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
policyID={policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_REPORT_FIELDS_ENABLED}
+ shouldBeBlocked={PolicyUtils.hasAccountingConnections(policy)}
>
;
+type ReportFieldsAddListValuePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps;
function ReportFieldsAddListValuePage({
+ policy,
route: {
params: {policyID, reportFieldID},
},
@@ -57,6 +61,7 @@ function ReportFieldsAddListValuePage({
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
policyID={policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_REPORT_FIELDS_ENABLED}
+ shouldBeBlocked={PolicyUtils.hasAccountingConnections(policy)}
>
;
+type ReportFieldsEditValuePageProps = WithPolicyAndFullscreenLoadingProps & StackScreenProps;
function ReportFieldsEditValuePage({
+ policy,
route: {
params: {policyID, valueIndex},
},
@@ -63,6 +67,7 @@ function ReportFieldsEditValuePage({
accessVariants={[CONST.POLICY.ACCESS_VARIANTS.ADMIN, CONST.POLICY.ACCESS_VARIANTS.PAID]}
policyID={policyID}
featureName={CONST.POLICY.MORE_FEATURES.ARE_REPORT_FIELDS_ENABLED}
+ shouldBeBlocked={PolicyUtils.hasAccountingConnections(policy)}
>
!disabledListValue).length;
@@ -82,7 +84,7 @@ function ReportFieldsInitialValuePage({
[availableListValuesLength, policy?.fieldList, translate],
);
- if (!reportField) {
+ if (!reportField || hasAccountingConnections) {
return ;
}
diff --git a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx
index 510c6ff8f54d..adbe33397950 100644
--- a/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx
+++ b/src/pages/workspace/reportFields/ReportFieldsListValuesPage.tsx
@@ -22,6 +22,7 @@ import useWindowDimensions from '@hooks/useWindowDimensions';
import * as ReportField from '@libs/actions/Policy/ReportField';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
import type {SettingsNavigatorParamList} from '@navigation/types';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
@@ -97,6 +98,7 @@ function ReportFieldsListValuesPage({
return [{data, isDisabled: false}];
}, [disabledListValues, listValues, policy?.fieldList, reportFieldID, selectedValues, translate]);
+ const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy);
const shouldShowEmptyState = Object.values(listValues ?? {}).length <= 0;
const selectedValuesArray = Object.keys(selectedValues).filter((key) => selectedValues[key]);
@@ -136,7 +138,7 @@ function ReportFieldsListValuesPage({
};
const openListValuePage = (valueItem: ValueListItem) => {
- if (valueItem.index === undefined) {
+ if (valueItem.index === undefined || hasAccountingConnections) {
return;
}
@@ -145,12 +147,26 @@ function ReportFieldsListValuesPage({
setSelectedValues({});
};
- const getCustomListHeader = () => (
-
- {translate('common.name')}
- {translate('statusPage.status')}
-
- );
+ const getCustomListHeader = () => {
+ const header = (
+
+ {translate('common.name')}
+ {translate('statusPage.status')}
+
+ );
+ if (!hasAccountingConnections) {
+ return header;
+ }
+ return {header};
+ };
const getHeaderButtons = () => {
const options: Array>> = [];
@@ -269,9 +285,9 @@ function ReportFieldsListValuesPage({
title={translate('workspace.reportFields.listValues')}
onBackButtonPress={Navigation.goBack}
>
- {!isSmallScreenWidth && getHeaderButtons()}
+ {!isSmallScreenWidth && !hasAccountingConnections && getHeaderButtons()}
- {isSmallScreenWidth && {getHeaderButtons()}}
+ {isSmallScreenWidth && {!hasAccountingConnections && getHeaderButtons()}}
{translate('workspace.reportFields.listInputSubtitle')}
@@ -285,7 +301,7 @@ function ReportFieldsListValuesPage({
)}
{!shouldShowEmptyState && (
Navigation.navigate(ROUTES.WORKSPACE_EDIT_REPORT_FIELDS_INITIAL_VALUE.getRoute(policyID, reportFieldID))}
/>
{isListFieldType && (
@@ -98,16 +100,18 @@ function ReportFieldsSettingsPage({
onPress={() => Navigation.navigate(ROUTES.WORKSPACE_REPORT_FIELDS_LIST_VALUES.getRoute(policyID, reportFieldID))}
/>
)}
-
-
+ {!hasAccountingConnections && (
+
+
+ )}
setIsDeleteModalVisible(false)}
shouldSetModalVisibility={false}
diff --git a/src/pages/workspace/reportFields/ReportFieldsValueSettingsPage.tsx b/src/pages/workspace/reportFields/ReportFieldsValueSettingsPage.tsx
index 209be2be26b1..977e64c882f1 100644
--- a/src/pages/workspace/reportFields/ReportFieldsValueSettingsPage.tsx
+++ b/src/pages/workspace/reportFields/ReportFieldsValueSettingsPage.tsx
@@ -14,6 +14,7 @@ import useLocalize from '@hooks/useLocalize';
import useThemeStyles from '@hooks/useThemeStyles';
import * as ReportField from '@libs/actions/Policy/ReportField';
import Navigation from '@libs/Navigation/Navigation';
+import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
import type {SettingsNavigatorParamList} from '@navigation/types';
import NotFoundPage from '@pages/ErrorPage/NotFoundPage';
@@ -56,7 +57,9 @@ function ReportFieldsValueSettingsPage({
return [reportFieldValue, reportFieldDisabledValue];
}, [formDraft?.disabledListValues, formDraft?.listValues, policy?.fieldList, reportFieldID, valueIndex]);
- if (!currentValueName) {
+ const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy);
+
+ if (!currentValueName || hasAccountingConnections) {
return ;
}
diff --git a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx
index 50b3f8394584..62d54a6be641 100644
--- a/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx
+++ b/src/pages/workspace/reportFields/WorkspaceReportFieldsPage.tsx
@@ -17,7 +17,9 @@ import ListItemRightCaretWithLabel from '@components/SelectionList/ListItemRight
import TableListItem from '@components/SelectionList/TableListItem';
import type {ListItem} from '@components/SelectionList/types';
import Text from '@components/Text';
+import TextLink from '@components/TextLink';
import WorkspaceEmptyStateSection from '@components/WorkspaceEmptyStateSection';
+import useEnvironment from '@hooks/useEnvironment';
import useLocalize from '@hooks/useLocalize';
import useResponsiveLayout from '@hooks/useResponsiveLayout';
import useTheme from '@hooks/useTheme';
@@ -26,7 +28,9 @@ import useWindowDimensions from '@hooks/useWindowDimensions';
import * as DeviceCapabilities from '@libs/DeviceCapabilities';
import Navigation from '@libs/Navigation/Navigation';
import type {FullScreenNavigatorParamList} from '@libs/Navigation/types';
+import * as PolicyUtils from '@libs/PolicyUtils';
import * as ReportUtils from '@libs/ReportUtils';
+import * as WorkspaceReportFieldUtils from '@libs/WorkspaceReportFieldUtils';
import AccessOrNotFoundWrapper from '@pages/workspace/AccessOrNotFoundWrapper';
import * as ReportField from '@userActions/Policy/ReportField';
import CONST from '@src/CONST';
@@ -55,6 +59,7 @@ function WorkspaceReportFieldsPage({
const theme = useTheme();
const {translate} = useLocalize();
const isFocused = useIsFocused();
+ const {environmentURL} = useEnvironment();
const [policy] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY}${policyID}`);
const filteredPolicyFieldList = useMemo(() => {
if (!policy?.fieldList) {
@@ -92,14 +97,14 @@ function WorkspaceReportFieldsPage({
rightElement: (
),
})),
isDisabled: false,
},
];
- }, [filteredPolicyFieldList, policy, selectedReportFields]);
+ }, [filteredPolicyFieldList, policy, selectedReportFields, translate]);
const updateSelectedReportFields = (item: ReportFieldForList) => {
const fieldKey = ReportUtils.getReportFieldKey(item.fieldID);
@@ -129,6 +134,9 @@ function WorkspaceReportFieldsPage({
const isLoading = policy === undefined;
const shouldShowEmptyState =
Object.values(filteredPolicyFieldList).filter((reportField) => reportField.pendingAction !== CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE).length <= 0 && !isLoading;
+ const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy);
+ const isConnectedToAccounting = Object.keys(policy?.connections ?? {}).length > 0;
+ const currentConnectionName = PolicyUtils.getCurrentConnectionName(policy);
const getHeaderButtons = () => {
const options: Array>> = [];
@@ -168,16 +176,43 @@ function WorkspaceReportFieldsPage({
);
};
- const getCustomListHeader = () => (
-
- {translate('common.name')}
- {translate('common.type')}
-
- );
+ const getCustomListHeader = () => {
+ const header = (
+
+ {translate('common.name')}
+ {translate('common.type')}
+
+ );
+ if (!hasAccountingConnections) {
+ return header;
+ }
+ return {header};
+ };
const getHeaderText = () => (
- {translate('workspace.reportFields.subtitle')}
+ {isConnectedToAccounting ? (
+
+ {`${translate('workspace.reportFields.importedFromAccountingSoftware')} `}
+
+ {`${currentConnectionName} ${translate('workspace.accounting.settings')}`}
+
+ .
+
+ ) : (
+ {translate('workspace.reportFields.subtitle')}
+ )}
);
@@ -199,9 +234,9 @@ function WorkspaceReportFieldsPage({
title={translate('workspace.common.reportFields')}
shouldShowBackButton={isSmallScreenWidth}
>
- {!isSmallScreenWidth && getHeaderButtons()}
+ {!isSmallScreenWidth && !hasAccountingConnections && getHeaderButtons()}
- {isSmallScreenWidth && {getHeaderButtons()}}
+ {isSmallScreenWidth && {!hasAccountingConnections && getHeaderButtons()}}
{
+ if (!PolicyUtils.isControlPolicy(policy)) {
+ Navigation.navigate(ROUTES.WORKSPACE_UPGRADE.getRoute(route.params.policyID, CONST.UPGRADE_FEATURE_INTRO_MAPPING.glCodes.alias));
+ return;
+ }
Navigation.navigate(ROUTES.WORKSPACE_TAG_GL_CODE.getRoute(route.params.policyID, route.params.orderWeight, currentPolicyTag.name));
};
diff --git a/src/pages/workspace/taxes/WorkspaceEditTaxPage.tsx b/src/pages/workspace/taxes/WorkspaceEditTaxPage.tsx
index 66703679569f..08e7be149ad0 100644
--- a/src/pages/workspace/taxes/WorkspaceEditTaxPage.tsx
+++ b/src/pages/workspace/taxes/WorkspaceEditTaxPage.tsx
@@ -37,10 +37,11 @@ function WorkspaceEditTaxPage({
const {translate} = useLocalize();
const currentTaxRate = PolicyUtils.getTaxByID(policy, taxID);
const [isDeleteModalVisible, setIsDeleteModalVisible] = useState(false);
- const canEdit = policy && PolicyUtils.canEditTaxRate(policy, taxID);
+ const canEditTaxRate = policy && PolicyUtils.canEditTaxRate(policy, taxID);
const hasAccountingConnections = PolicyUtils.hasAccountingConnections(policy);
+ const canEditTaxCode = !PolicyUtils.isControlPolicy(policy);
- const shouldShowDeleteMenuItem = canEdit && !hasAccountingConnections;
+ const shouldShowDeleteMenuItem = canEditTaxRate && !hasAccountingConnections;
const toggleTaxRate = () => {
if (!currentTaxRate) {
@@ -87,7 +88,7 @@ function WorkspaceEditTaxPage({
isOn={!currentTaxRate?.isDisabled}
accessibilityLabel={translate('workspace.taxes.actions.enable')}
onToggle={toggleTaxRate}
- disabled={!canEdit}
+ disabled={!canEditTaxRate}
/>
@@ -122,6 +123,22 @@ function WorkspaceEditTaxPage({
onPress={() => Navigation.navigate(ROUTES.WORKSPACE_TAX_VALUE.getRoute(`${policyID}`, taxID))}
/>
+ clearTaxRateFieldError(policyID, taxID, 'code')}
+ >
+ Navigation.navigate(ROUTES.WORKSPACE_TAX_CODE.getRoute(`${policyID}`, taxID))}
+ />
+
{shouldShowDeleteMenuItem && (