Skip to content

Commit

Permalink
conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
Gonals committed Apr 23, 2024
2 parents a436acc + b386889 commit 4a9708c
Show file tree
Hide file tree
Showing 123 changed files with 2,174 additions and 1,100 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# - git diff is used to see the files that were added on this branch
# - gh pr view is used to list files touched by this PR. Git diff may give false positives if the branch isn't up-to-date with main
# - wc counts the words in the result of the intersection
count_new_js=$(comm -1 -2 <(git diff --name-only --diff-filter=A origin/main HEAD -- 'src/*.js' '__mocks__/*.js' '.storybook/*.js' 'assets/*.js' 'config/*.js' 'desktop/*.js' 'jest/*.js' 'scripts/*.js' 'tests/*.js' 'web/*.js' 'workflow_tests/*.js' '.github/libs/*.js' '.github/scripts/*.js') <(gh pr view ${{ github.event.pull_request.number }} --json files | jq -r '.files | map(.path) | .[]') | wc -l)
count_new_js=$(comm -1 -2 <(git diff --name-only --diff-filter=A origin/main HEAD -- 'src/*.js' '__mocks__/*.js' '.storybook/*.js' 'assets/*.js' 'config/*.js' 'desktop/*.js' 'jest/*.js' 'scripts/*.js' 'tests/*.js' 'workflow_tests/*.js' '.github/libs/*.js' '.github/scripts/*.js') <(gh pr view ${{ github.event.pull_request.number }} --json files | jq -r '.files | map(.path) | .[]') | wc -l)
if [ "$count_new_js" -gt "0" ]; then
echo "ERROR: Found new JavaScript files in the project; use TypeScript instead."
exit 1
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ If you're using another operating system, you will need to ensure `mkcert` is in
For an M1 Mac, read this [SO](https://stackoverflow.com/questions/64901180/how-to-run-cocoapods-on-apple-silicon-m1) for installing cocoapods.

* If you haven't already, install Xcode tools and make sure to install the optional "iOS Platform" package as well. This installation may take awhile.
* After installation, check in System Settings that there's no update for Xcode. Otherwise, you may encounter issues later that don't explain that you solve them by updating Xcode.
* Install project gems, including cocoapods, using bundler to ensure everyone uses the same versions. In the project root, run: `bundle install`
* If you get the error `Could not find 'bundler'`, install the bundler gem first: `gem install bundler` and try again.
* If you are using MacOS and get the error `Gem::FilePermissionError` when trying to install the bundler gem, you're likely using system Ruby, which requires administrator permission to modify. To get around this, install another version of Ruby with a version manager like [rbenv](https://github.com/rbenv/rbenv#installation).
Expand Down
14 changes: 11 additions & 3 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@ apply plugin: "com.android.application"
apply plugin: "org.jetbrains.kotlin.android"
apply plugin: "com.facebook.react"
apply plugin: "com.google.firebase.firebase-perf"
apply plugin: "fullstory"
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"

/**
* This is the configuration block to customize your React Native Android app.
* By default you don't need to apply any configuration, just uncomment the lines you need.
*/

/* Fullstory settings */
fullstory {
org 'o-1WN56P-na1'
enabledVariants 'all'
}

react {
/* Folders */
// The root of your project, i.e. where "package.json" lives. Default is '..'
Expand Down Expand Up @@ -98,8 +106,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
versionCode 1001046402
versionName "1.4.64-2"
versionCode 1001046406
versionName "1.4.64-6"
// 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 Expand Up @@ -162,7 +170,7 @@ android {
signingConfig null
// buildTypes take precedence over productFlavors when it comes to the signing configuration,
// thus we need to manually set the signing config, so that the e2e uses the debug config again.
// In other words, the signingConfig setting above will be ignored when we build the flavor in release mode.
// In other words, the signingConfig setting above will be ignored when we build the flavor in release mode.
productFlavors.all { flavor ->
// All release builds should be signed with the release config ...
flavor.signingConfig signingConfigs.release
Expand Down
6 changes: 5 additions & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ buildscript {
repositories {
google()
mavenCentral()
maven {url "https://maven.fullstory.com"}
}
dependencies {
classpath("com.android.tools.build:gradle")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("com.google.gms:google-services:4.3.4")
classpath("com.google.firebase:firebase-crashlytics-gradle:2.7.1")
classpath("com.google.firebase:perf-plugin:1.4.1")
// Fullstory integration
classpath ("com.fullstory:gradle-plugin-local:1.45.1")

// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
Expand Down Expand Up @@ -70,7 +74,7 @@ allprojects {
// 'mapbox' is the fixed username for Mapbox's Maven repository.
username = 'mapbox'

// The value for password is read from the 'MAPBOX_DOWNLOADS_TOKEN' gradle property.
// The value for password is read from the 'MAPBOX_DOWNLOADS_TOKEN' gradle property.
// Run "npm run setup-mapbox-sdk" to set this property in «USER_HOME»/.gradle/gradle.properties

// Example gradle.properties entry:
Expand Down
17 changes: 17 additions & 0 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,23 @@ const defaultPlugins = [
// source code transformation as we do not use class property assignment.
'transform-class-properties',

/* Fullstory */
[
'@fullstory/react-native',
{
version: '1.4.0',
org: 'o-1WN56P-na1',
enabledVariants: 'all',
},
],
[
'@fullstory/babel-plugin-annotate-react',
{
native: true,
setFSTagName: true,
},
],

// Keep it last
'react-native-reanimated/plugin',
];
Expand Down
2 changes: 1 addition & 1 deletion config/webpack/webpack.common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const getCommonConfiguration = ({file = '.env', platform = 'web'}: Environment):
{from: 'web/apple-touch-icon.png'},
{from: 'assets/images/expensify-app-icon.svg'},
{from: 'web/manifest.json'},
{from: 'web/gtm.js'},
{from: 'web/thirdPartyScripts.js'},
{from: 'assets/css', to: 'css'},
{from: 'assets/fonts/web', to: 'fonts'},
{from: 'assets/sounds', to: 'sounds'},
Expand Down
69 changes: 66 additions & 3 deletions contributingGuides/STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,14 +68,48 @@ export {
}
```

Using arrow functions is the preferred way to write an anonymous function such as a callback method.
Using named functions is the preferred way to write a callback method.

```javascript
// Bad
someArray.map(function (item) {...});
people.map(function (item) {/* Long and complex logic */});
people.map((item) => {/* Long and complex logic with many inner loops*/});
useEffect/useMemo/useCallback(() => {/* Long and complex logic */}, []);

// Good
someArray.map((item) => {...});
function mappingPeople(person) {/* Long and complex logic */};
people.map(mappingPeople);
useEffect/useMemo/useCallback(function handlingConnection() {/* Long and complex logic */}, []);
```

You can still use arrow function for declarations or simple logics to keep them readable.

```javascript
// Bad
randomList.push({
onSelected: Utils.checkIfAllowed(function checkTask() { return Utils.canTeamUp(people); }),
});
routeList.filter(function checkIsActive(route) {
return route.isActive;
});

// Good
randomList.push({
onSelected: Utils.checkIfAllowed(() => Utils.canTeamUp(people)),
});
routeList.filter((route) => route.isActive);
const myFunction = () => {...};
const person = { getName: () => {} };
Utils.connect({
callback: (val) => {},
});
useEffect(() => {
if (isFocused) {
return;
}
setError(null, {});
}, [isFocused]);

```

Empty functions (noop) should be declare as arrow functions with no whitespace inside. Avoid _.noop()
Expand Down Expand Up @@ -112,6 +146,35 @@ if (someCondition) {
}
```

## Object / Array Methods

We have standardized on using [underscore.js](https://underscorejs.org/) methods for objects and collections instead of the native [Array instance methods](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#instance_methods). This is mostly to maintain consistency, but there are some type safety features and conveniences that underscore methods provide us e.g. the ability to iterate over an object and the lack of a `TypeError` thrown if a variable is `undefined`.

```javascript
// Bad
myArray.forEach(item => doSomething(item));
// Good
_.each(myArray, item => doSomething(item));

// Bad
const myArray = Object.keys(someObject).map((key) => doSomething(someObject[key]));
// Good
const myArray = _.map(someObject, (value, key) => doSomething(value));

// Bad
myCollection.includes('item');
// Good
_.contains(myCollection, 'item');

// Bad
const modifiedArray = someArray.filter(filterFunc).map(mapFunc);
// Good
const modifiedArray = _.chain(someArray)
.filter(filterFunc)
.map(mapFunc)
.value();
```

## Accessing Object Properties and Default Values

Use `lodashGet()` to safely access object properties and `||` to short circuit null or undefined values that are not guaranteed to exist in a consistent way throughout the codebase. In the rare case that you want to consider a falsy value as usable and the `||` operator prevents this then be explicit about this in your code and check for the type.
Expand Down
2 changes: 1 addition & 1 deletion contributingGuides/TS_STYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,7 @@ _.each(arr, () => {});

// GOOD
var arr = [];
arr.forEach(() => {});
arr.forEach(function loopArr() {});

// BAD
lodashGet(object, ['foo'], 'bar');
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
---
title: Assign or remove a Copilot
description: Safely delegate tasks without sharing login information.
---

You can safely delegate tasks to someone else without sharing your login information by assigning them as your Copilot. Your copilot can access your Expensify account through their own account to:
* Prepare expenses on your behalf
* Approve and reimburse expense reports on your behalf (Full Access Copilots only)
* View and make changes to your account, domain, and workspace settings
* View all expenses visible from your account

# Assign a Copilot

1. Hover over Settings and click **Account**.
2. Under Account Details, scroll down to the Copilot: Delegated Access section.
3. Enter the email address or phone number for the person you want to assign as your Copilot.
4. Select whether you want to give your Copilot Full or Submit Only access.
* **Full Access**: Your Copilot will have full access to your account. Nearly every action you can do and everything you can see in your account will also be available to your Copilot. However, Copilots do not have the ability to add or remove other Copilots from your account.
* **Submit Only Access**: Your Copilot will have the same access and limitations as a Full Access Copilot, but they will not be able to approve reports on your behalf—they can only submit them.
5. Click **Invite Copilot**.

If your Copilot already has an Expensify account, they will get an email notifying them that they can now also access your account from within their own. If they do not have an Expensify account, they will get an email with a link to create one. Once created, they will be able to access your account from within their own.

# Remove a Copilot

{% include info.html %}
This action must be completed by the account owner. Copilots cannot remove other Copilots from an account.
{% include end-info.html %}

1. Hover over Settings and click **Account**.
2. Under Account Details, scroll down to the Copilot: Delegated Access section.
3. Click the red X next to the copilot to remove them.

# FAQs

**Can I only have one Copilot?**

You can assign as many Copilots as you like—there is no limit.
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: Create a report approval workflow
description: Set up an approval workflow automation for employee reports
---
<div id="expensify-classic" markdown="1">

Expensify allows Workspace Admins to create workflows and automations that determine how expense reports are approved for the workspace. You can choose from three different workflows that either:
- Allow all submitted expenses to be automatically approved (if they don’t have any violations).
- Assign one approver for all reports under the workspace.
- Set up multi-level approvals for more complex workflows.

# Set approval workflow

1. Hover over Settings, then click **Workspaces**.
2. Click the desired workspace name.
3. Click the **Members** tab on the left.
4. Scroll down to the Approval Mode section.
5. Select an approval mode.
- **Submit and Close**: No approval is required. Once a report is submitted, it will be automatically approved and closed. This option may be useful if your expense approvals occur in another system or if the submitter and approver are the same person.
- **Submit and Approve**: All reports go to one person that you assign as the approver. Once a report is submitted, it is sent to the approver. This is the default option.
- **Advanced Approval**: Allows for more complex workflows, like assigning different approvers for different employees or requiring secondary approvals for expenses that exceed a set limit.

To add to your approval workflow, you can also set up approval rules for specific categories and tags.

</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: Require review for over-limit expenses
description: Require a manual review for expenses that exceed a set amount
---
<div id="expensify-classic" markdown="1">

You can set rules that require a manual review for expenses that exceed a specific amount. These rules can be set for all expenses under a workspace and/or for a specific member of your workspace.

{% include info.html %}
These rules do not prohibit purchases over this limit amount. They only ensure that expenses over the limit require a manual review.
{% include end-info.html %}

# Set a manual approval rule for over-limit expenses

To set approval limits for expenses submitted to a workspace,
1. Hover over Settings, then click **Workspaces**.
2. Click the desired workspace name.
3. Click the **Members** tab on the left.
4. Scroll down to the Approval Mode section to where it says Expense Approvals.
5. In the “Manually approve all expenses over:” field, enter the expense limit amount.

Any expenses that exceed the set limit will now require a manual review, even if the approval workflow does not require manual approval.

# Set an over-limit approver for a member

When over-limit approvals are set for a specific member, a secondary approver will be required when the member submits a report that contains expenses exceeding the limit amount. If the member is an approver for other members’ reports, the approval limit applies to those reports as well.

For example, if you want to allow a project manager to review expenses under $500 but have a department head review expenses over $500, you can assign the department head as the project manager’s over-limit approver.

{% include info.html %}
To set expense limits for specific workspace members, your workspace must use Advanced Approvals as the report approval workflow.
{% include end-info.html %}

To set an over-limit approver for a specific member of your workspace,
1. Hover over Settings, then click **Workspaces**.
2. Click the desired workspace name.
3. Click the **Members** tab on the left.
4. Click **Settings** next to the desired member.
5. In the “If report total is over” field, enter the amount that will require this member’s reports to need a secondary review. This limit also applies to reports that the member is in charge of reviewing.
6. Click the “Then approves to” dropdown and select the secondary approver.
7. Click **Save**.

</div>



Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Set a random report audit schedule
description: Randomly audit a percentage of compliant reports
---
<div id="expensify-classic" markdown="1">

Expensify automatically flags reports that contain inaccurate or non-compliant expenses for review. However, you can also choose to randomly audit a percentage of compliant reports.

To set a random audit schedule,
1. Hover over Settings, then click **Workspaces**.
2. Click the desired workspace name.
3. Click the **Members** tab on the left.
4. Scroll down to the Expense Approvals heading under the Approval Modes section.
5. In the “Randomly route reports for manual approval” field, enter the percentage of reports that you want to be randomly audited. The default is set at 5% (or 1 in 20 reports).
6. Click **Save**.

</div>




4 changes: 4 additions & 0 deletions ios/NewExpensify.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,7 @@
"${PODS_ROOT}/Target Support Files/Pods-NewExpensify-NewExpensifyTests/Pods-NewExpensify-NewExpensifyTests-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework",
"${BUILT_PRODUCTS_DIR}/Turf/Turf.framework",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FullStory/FullStory.framework/FullStory",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents",
Expand All @@ -692,6 +693,7 @@
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FullStory.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework",
Expand Down Expand Up @@ -735,6 +737,7 @@
"${PODS_ROOT}/Target Support Files/Pods-NewExpensify/Pods-NewExpensify-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/MapboxMaps/MapboxMaps.framework",
"${BUILT_PRODUCTS_DIR}/Turf/Turf.framework",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/FullStory/FullStory.framework/FullStory",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCommon/MapboxCommon.framework/MapboxCommon",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxCoreMaps/MapboxCoreMaps.framework/MapboxCoreMaps",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/MapboxMobileEvents/MapboxMobileEvents.framework/MapboxMobileEvents",
Expand All @@ -746,6 +749,7 @@
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMaps.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Turf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FullStory.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCommon.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxCoreMaps.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MapboxMobileEvents.framework",
Expand Down
7 changes: 6 additions & 1 deletion ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>1.4.64.2</string>
<string>1.4.64.6</string>
<key>FullStory</key>
<dict>
<key>OrgId</key>
<string>o-1WN56P-na1</string>
</dict>
<key>ITSAppUsesNonExemptEncryption</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
Expand Down
Loading

0 comments on commit 4a9708c

Please sign in to comment.