Skip to content

Commit

Permalink
Merge branch 'main' into fix-short-mention-regex
Browse files Browse the repository at this point in the history
  • Loading branch information
FitseTLT committed Nov 22, 2024
2 parents 212c42f + 2b31276 commit 934f0a0
Show file tree
Hide file tree
Showing 275 changed files with 6,426 additions and 1,405 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ONYX_METRICS=false
USE_THIRD_PARTY_SCRIPTS=false

EXPENSIFY_ACCOUNT_ID_ACCOUNTING=-1
EXPENSIFY_ACCOUNT_ID_ACCOUNTS_PAYABLE=-1
EXPENSIFY_ACCOUNT_ID_ADMIN=-1
EXPENSIFY_ACCOUNT_ID_BILLS=-1
EXPENSIFY_ACCOUNT_ID_CHRONOS=-1
Expand Down
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c
- [ ] I verified that comments were added to code that is not self explanatory
- [ ] I verified that any new or modified comments were clear, correct English, and explained "why" the code was doing something instead of only explaining "what" the code was doing.
- [ ] I verified any copy / text shown in the product is localized by adding it to `src/languages/*` files and using the [translation method](https://github.com/Expensify/App/blob/4bd99402cebdf4d7394e0d1f260879ea238197eb/src/components/withLocalize.js#L60)
- [ ] If any non-english text was added/modified, I verified the translation was requested/reviewed in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
- [ ] If any non-english text was added/modified, I used [JaimeGPT](https://chatgpt.com/g/g-2dgOQl5VM-english-to-spanish-translator-aka-jaimegpt) to get English > Spanish translation. I then posted it in #expensify-open-source and it was approved by an internal Expensify engineer. Link to Slack message:
- [ ] I verified all numbers, amounts, dates and phone numbers shown in the product are using the [localization methods](https://github.com/Expensify/App/blob/4bd99402cebdf4d7394e0d1f260879ea238197eb/src/components/withLocalize.js#L60-L68)
- [ ] I verified any copy / text that was added to the app is grammatically correct in English. It adheres to proper capitalization guidelines (note: only the first word of header/labels should be capitalized), and is either coming verbatim from figma or has been approved by marketing (in order to get marketing approval, ask the Bug Zero team member to add the Waiting for copy label to the issue)
- [ ] I verified proper file naming conventions were followed for any new files or renamed files. All non-platform specific files are named after what they export and are not named "index.js". All platform-specific files are named for the platform the code supports as outlined in the README.
Expand Down
4 changes: 2 additions & 2 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1009006400
versionName "9.0.64-0"
versionCode 1009006504
versionName "9.0.65-4"
// Supported language variants must be declared here to avoid from being removed during the compilation.
// This also helps us to not include unnecessary language variants in the APK.
resConfigs "en", "es"
Expand Down
2 changes: 1 addition & 1 deletion contributingGuides/PERFORMANCE_METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Project is using Firebase for tracking these metrics. However, not all of them a
| `js_loaded` || The time it takes for the JavaScript bundle to load. <br><br>**Platforms:** Android, iOS | **Android:** Starts in the `onCreate` method.<br><br>**iOS:** Starts in the AppDelegate's `didFinishLaunchingWithOptions` method. | Stops at the first render of the app via native module on the JS side. |
| `_app_in_foreground` || The time when the app is running in the foreground and available to the user.<br><br>**Platforms:** Android, iOS | **Android:** Starts when the first activity to reach the foreground has its `onResume()` method called. <br><br>**iOS:** Starts when the application receives the `UIApplicationDidBecomeActiveNotification` notification. | **Android:** Stops when the last activity to leave the foreground has its `onStop()` method called. <br><br>**iOS:** Stops when it receives the `UIApplicationWillResignActiveNotification` notification. |
| `_app_in_background` || Time when the app is running in the background.<br><br>**Platforms:** Android, iOS | **Android:** Starts when the last activity to leave the foreground has its `onStop()` method called. <br><br>**iOS:** Starts when the application receives the `UIApplicationWillResignActiveNotification` notification. | **Android:** Stops when the first activity to reach the foreground has its `onResume()` method called. <br><br>**iOS:** Stops when it receives the `UIApplicationDidBecomeActiveNotification` notification. |
| `sidebar_loaded` | | Time taken for the Sidebar to load.<br><br>**Platforms:** All | Starts when the Sidebar is mounted. | Stops when the LHN finishes laying out. |
| `sidebar_loaded` | | Time taken for the Sidebar to load.<br><br>**Platforms:** All | Starts when the Sidebar is mounted. | Stops when the LHN finishes laying out. |
| `calc_most_recent_last_modified_action` || Time taken to find the most recently modified report action or report.<br><br>**Platforms:** All | Starts when the app reconnects to the network | Ends when the app reconnects to the network and the most recent report action or report is found. |
| `open_search` || Time taken to open up the Search Router.<br><br>**Platforms:** All | Starts when the Search Router icon in LHN is pressed. | Stops when the list of available options finishes laying out. |
| `load_search_options` || Time taken to generate the list of options used in the Search Router.<br><br>**Platforms:** All | Starts when the `getSearchOptions` function is called. | Stops when the list of available options is generated. |
Expand Down
64 changes: 56 additions & 8 deletions contributingGuides/STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,20 +477,68 @@ if (ref.current && 'getBoundingClientRect' in ref.current) {

### Default value for inexistent IDs

Use `'-1'` or `-1` when there is a possibility that the ID property of an Onyx value could be `null` or `undefined`.
Use `CONST.DEFAULT_NUMBER_ID` when there is a possibility that the number ID property of an Onyx value could be `null` or `undefined`. **Do not default string IDs to any value!**

> Why? The default number ID (currently set to `0`, which matches the backend’s default) is a falsy value. This makes it compatible with conditions that check if an ID is set, such as `if (!ownerAccountID) {`. Since it’s stored as a constant, it can easily be changed across the codebase if needed.
>
> However, defaulting string IDs to `'0'` breaks such conditions because `'0'` is a truthy value in JavaScript. Defaulting to `''` avoids this issue, but it can cause crashes or bugs if the ID is passed to Onyx. This is because `''` could accidentally subscribe to an entire Onyx collection instead of a single record.
>
> To address both problems, string IDs **should not have a default value**. This approach allows conditions like `if (!policyID) {` to work correctly, as `undefined` is a falsy value. At the same time, it prevents Onyx bugs: if `policyID` is used to subscribe to a specific Onyx record, a `policy_undefined` key will be used, and Onyx won’t return any records.
>
> In case you are confused or find a situation where you can't apply the rules mentioned above, please raise your question in the [`#expensify-open-source`](https://expensify.slack.com/archives/C01GTK53T8Q) Slack channel.
``` ts
// BAD
const foo = report?.reportID ?? '';
const bar = report?.reportID ?? '0';

report ? report.reportID : '0';
report ? report.reportID : '';
const accountID = report?.ownerAccountID ?? -1;
const policyID = report?.policyID ?? '-1';
const managerID = report ? report.managerID : 0;

// GOOD
const foo = report?.reportID ?? '-1';
const accountID = report?.ownerAccountID ?? CONST.DEFAULT_NUMBER_ID;
const policyID = report?.policyID;
const managerID = report ? report.managerID : CONST.DEFAULT_NUMBER_ID;
```
Here are some common cases you may face when fixing your code to remove the old/bad default values.
#### **Case 1**: Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
```diff
-Report.getNewerActions(newestActionCurrentReport?.reportID ?? '-1', newestActionCurrentReport?.reportActionID ?? '-1');
+Report.getNewerActions(newestActionCurrentReport?.reportID, newestActionCurrentReport?.reportActionID);
```
> error TS2345: Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'.
We need to change `Report.getNewerActions()` arguments to allow `undefined`. By doing that we could add a condition that return early if one of the parameters are falsy, preventing the code (which is expecting defined IDs) from executing.
```diff
-function getNewerActions(reportID: string, reportActionID: string) {
+function getNewerActions(reportID: string | undefined, reportActionID: string | undefined) {
+ if (!reportID || !reportActionID) {
+ return;
+ }
```
#### **Case 2**: Type 'undefined' cannot be used as an index type.
```diff
function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = false, updatedTransaction, isFromReviewDuplicates = false}: MoneyRequestViewProps) {
const [parentReportActions] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${parentReportID}`, {
canEvict: false,
});
- const parentReportAction = parentReportActions?.[report?.parentReportActionID ?? '-1'];
+ const parentReportAction = parentReportActions?.[report?.parentReportActionID];
```
> error TS2538: Type 'undefined' cannot be used as an index type.
This error is inside a component, so we can't simply use early return conditions here. Instead, we can check if `report?.parentReportActionID` is defined, if it is we can safely use it to find the record inside `parentReportActions`. If it's not defined, we just return `undefined`.
report ? report.reportID : '-1';
```diff
function MoneyRequestView({report, shouldShowAnimatedBackground, readonly = false, updatedTransaction, isFromReviewDuplicates = false}: MoneyRequestViewProps) {
- const parentReportAction = parentReportActions?.[report?.parentReportActionID ?? '-1'];
+ const parentReportAction = report?.parentReportActionID ? parentReportActions?.[report.parentReportActionID] : undefined;
```
### Extract complex types
Expand Down
8 changes: 8 additions & 0 deletions desktop/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ const {DESKTOP_SHORTCUT_ACCELERATOR, LOCALES} = CONST;
// geolocation api (window.navigator.geolocation.getCurrentPosition) to work on desktop.
// Source: https://github.com/electron/electron/blob/98cd16d336f512406eee3565be1cead86514db7b/docs/api/environment-variables.md#google_api_key
process.env.GOOGLE_API_KEY = CONFIG.GCP_GEOLOCATION_API_KEY;
/**
* Suppresses Content Security Policy (CSP) console warnings related to 'unsafe-eval'.
* This is required because:
* 1. Webpack utilizes eval() for module bundling
* 2. The application requires 'unsafe-eval' in CSP to function properly
* Note: CSP warnings are expected and unavoidable in this context
*/
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = CONFIG.ELECTRON_DISABLE_SECURITY_WARNINGS;

app.setName('New Expensify');

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ You can receive bills in three ways:
- Manual Upload: For physical bills, create a Bill in Expensify from the Reports page.

# Bill Pay Workflow
1. When a vendor or supplier sends a bill to Expensify, the document is automatically SmartScanned, and a Bill is created. This Bill is managed by the primary domain contact, who can view it on the Reports page within their default group policy.
1. When a vendor or supplier sends a bill to Expensify, the document is automatically SmartScanned, and a Bill is created. This Bill is managed by the primary domain contact, who can view it on the Reports page within their default group workspace.

2. Once the Bill is ready for processing, it follows the established approval workflow. As each person approves it, the Bill appears in the next approver’s Inbox. The final approver will pay the Bill using one of the available payment methods.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Welcome to the world of effortless expense tracking! Connecting your personal cr
## How to connect your personal card to import expenses
Importing your card or bank via Account Settings will:
Automatically sync your bank/card transactions with your Expensify account. These will merge seamlessly with any SmartScanned expenses in your account.
Generate IRS-compliant eReceipts, provided your Policy Admin has enabled this feature.
Generate IRS-compliant eReceipts, provided your Workspace Admin has enabled this feature.
Discover below the numerous ways to easily bring your personal card expenses into Expensify below.

### *Important terms to know:*
Expand Down Expand Up @@ -45,7 +45,7 @@ _Please note: an OFX file type will require no editing but not all banks' OFX fi
6. Set the date format to match your CSV and adjust the currency to match your bank account currency.
7. If you've previously imported expenses for the same card, choose the default layout of a previously uploaded spreadsheet.
8. Scroll down and select which columns map to the merchant, date and amount (as a number without a currency symbol) – these are required presets which must be assigned.
9. If applicable, you can also map specific Categories and Tags as long as you don't have an integration connection to your default group policy. If you have an integration connected, you'll want to add the Categories and Tags to the expense after the expense is uploaded.
9. If applicable, you can also map specific Categories and Tags as long as you don't have an integration connection to your default group workspace. If you have an integration connected, you'll want to add the Categories and Tags to the expense after the expense is uploaded.
10. Check the preview of your selection under *Output Preview*. If everything looks good, you can then select *Add Expenses*.
11. For checking accounts, you may need to "Flip Amount Sign" as transactions are often exported as negative amounts.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ Personal Liability: Users are allowed to delete company card expenses.

If you update the settings on an existing company card feed, the changes will apply to expenses imported after the date the setting is saved. The update will not affect previously imported expenses.

## Preferred policy
## Preferred workspace

Setting a preferred policy for a company card feed will ensure that the imported transactions are added to a report on the policy you set. This setting is useful when members are on multiple policies and need to ensure their company card expenses are reported to a particular policy.
Setting a preferred workspace for a company card feed will ensure that the imported transactions are added to a report on the workspace you set. This setting is useful when members are on multiple workspaces and need to ensure their company card expenses are reported to a particular workspace.

# How to use Scheduled Submit with company cards
All expenses must be placed on a report if they need to be approved; with Scheduled Submit, you no longer need to worry about the arduous task of employees creating their expenses, adding them to a report, and submitting them manually. All they need to do is SmartScan their receipts and Concierge will take care of the rest, on a variety of schedules that you can set according to your preferences!
Expand All @@ -41,11 +41,11 @@ Concierge won't automatically submit expenses on reports that have Expense Viola
An employee can add comments in the Expense Comment field or at the bottom of the report to clarify any details.

## Enable Scheduled Submit
Scheduled Submit is enabled in the Group Policy by navigating to Settings > Policies > Group > Policy Name > Reports > Scheduled Submit
Scheduled Submit is enabled in the Group Workspace by navigating to Settings > Workspaces > Group > Workspace Name > Reports > Scheduled Submit
Use the toggle to enable Scheduled Submit
Choose your desired frequency

If Scheduled Submit is disabled on the group policy level (or set to a manual frequency), and you have noticed expense reports are still automatically submitted to the group policy, it's likely Scheduled Submit is enabled on the user’s Individual Policy settings.
If Scheduled Submit is disabled on the group workspace level (or set to a manual frequency), and you have noticed expense reports are still automatically submitted to the group workspace, it's likely Scheduled Submit is enabled on the user’s Individual Workspace settings.

# How to connect company cards to an accounting integration

Expand All @@ -59,7 +59,7 @@ You're all done. After the account is set, exported expenses will be mapped to t
## Pooled GL account

To export credit card expenses to a pooled GL account:
Go to Settings > Policies > Group > Policy Name > Connections > Accounting Integrations > Configure
Go to Settings > Workspaces > Group > Workspace Name > Connections > Accounting Integrations > Configure
Select Credit Card / Charge Card / Bank Transaction as your Non-reimbursable export option.
Please review the Export Settings page for exporting Expense Reports to NetSuite
Select the Vendor/liability account you want to export all non-reimbursable expenses to.
Expand All @@ -86,7 +86,7 @@ It's important to note that eReceipts are not generated for lodging expenses. Mo

{% include faq-begin.md %}
## What plan/subscription is required in order to manage corporate cards?
Group Policy (Collect or Control plan only)
Group Workspace (Collect or Control plan only)
## When do my company card transactions import to Expensify?
Credit card transactions are imported to Expensify once they’re posted to the bank account. This usually takes 1-3 business days between the point of purchase and when the transactions populate in your account.

Expand Down
6 changes: 3 additions & 3 deletions docs/articles/expensify-classic/connections/Deel.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description: Automatically sync expenses from Expensify to Deel

# Overview

This guide is for business clients who want to set up policies and synchronize expenses from Expensify to Deel. This one-way synchronization ensures that Expensify becomes the definitive source for all employee expenses.
This guide is for business clients who want to set up workspaces and synchronize expenses from Expensify to Deel. This one-way synchronization ensures that Expensify becomes the definitive source for all employee expenses.

If you are a contractor or employee working for a company using Expensify, please refer to:

Expand All @@ -16,7 +16,7 @@ If you are a contractor or employee working for a company using Expensify, pleas

By integrating Expensify with Deel, you can utilize Expensify’s approval workflows to ensure timely payment through Deel for your team.

This process involves aligning user profiles and expense policies between Expensify and Deel. Once connected, Deel will scan for approved expenses from matched users included in selected workspaces for integration, allowing Deel to import these expenses for reimbursement.
This process involves aligning user profiles and expense workspaces between Expensify and Deel. Once connected, Deel will scan for approved expenses from matched users included in selected workspaces for integration, allowing Deel to import these expenses for reimbursement.

This synchronization is one-way. Expenses and receipts logged and approved in Expensify will sync to Deel. Expenses logged in Deel will not sync to Expensify.

Expand All @@ -27,7 +27,7 @@ This synchronization is one-way. Expenses and receipts logged and approved in Ex
To establish a connection, make sure you have the following:

- Deel Organization Manager permissions
- Expensify Admin permissions for policies you wish to integrate with Deel
- Expensify Admin permissions for workspaces you wish to integrate with Deel
- A paid Expensify subscription to approve expenses and sync them to Deel

Expensify Admin permissions can be intricate. Refer to [Expensify’s Introduction to Integration]([https://example.com](https://integrations.expensify.com/Integration-Server/doc/#introduction)) for more details.
Expand Down
Loading

0 comments on commit 934f0a0

Please sign in to comment.