Skip to content

Commit 6da93ec

Browse files
committed
merge main
2 parents 9ebda98 + 15463ca commit 6da93ec

File tree

207 files changed

+3825
-1801
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

207 files changed

+3825
-1801
lines changed

.github/workflows/deployNewHelp.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ jobs:
5858
# v4
5959
uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e
6060
with:
61-
node-version: '20.18.1'
61+
node-version: '20.19.1'
6262

6363
# Wil install the _help/package.js
6464
- name: Install Node.js Dependencies

.github/workflows/publishReactNativeAndroidArtifacts.yml

Lines changed: 56 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,28 @@ on:
1111
- Mobile-Expensify
1212

1313
jobs:
14-
publish:
15-
runs-on: ${{ github.repository_owner == 'Expensify' && 'ubuntu-latest-xl' || 'ubuntu-latest' }}
16-
strategy:
17-
matrix:
18-
is_hybrid: [true, false]
14+
verifyPatches:
15+
name: Verify React Native Patches
16+
runs-on: 'ubuntu-latest'
17+
outputs:
18+
build_targets: ${{ steps.getArtifactBuildTargets.outputs.BUILD_TARGETS }}
19+
hybrid_app_patches_hash: ${{ steps.getNewPatchesHash.outputs.HYBRID_APP_HASH }}
20+
standalone_patches_hash: ${{ steps.getNewPatchesHash.outputs.STANDALONE_APP_HASH }}
1921
steps:
20-
# v4
2122
- name: Checkout
2223
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
2324
with:
24-
submodules: ${{ matrix.is_hybrid }}
25+
submodules: true
2526
ref: ${{ github.event.before }}
2627
token: ${{ secrets.OS_BOTIFY_TOKEN }}
2728

2829
- name: Get previous patches hash
2930
id: getOldPatchesHash
3031
run: |
31-
if [[ "${{ matrix.is_hybrid }}" == "true" ]]; then
32-
echo "HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
33-
else
34-
echo "HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
35-
fi
32+
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
33+
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
3634
3735
- name: Get previous react-native version
38-
3936
id: getOldVersion
4037
run: echo "VERSION=$(jq -r '.dependencies["react-native"]' package.json)" >> "$GITHUB_OUTPUT"
4138

@@ -48,11 +45,8 @@ jobs:
4845
- name: Get new patches hash
4946
id: getNewPatchesHash
5047
run: |
51-
if [[ "${{ matrix.is_hybrid }}" == "true" ]]; then
52-
echo "HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
53-
else
54-
echo "HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
55-
fi
48+
echo "HYBRID_APP_HASH=$(./scripts/compute-patches-hash.sh patches Mobile-Expensify/patches)" >> "$GITHUB_OUTPUT"
49+
echo "STANDALONE_APP_HASH=$(./scripts/compute-patches-hash.sh patches)" >> "$GITHUB_OUTPUT"
5650
5751
- name: Get new react-native version
5852
id: getNewVersion
@@ -70,54 +64,75 @@ jobs:
7064
- name: Check if patches changed
7165
id: didPatchesChange
7266
run: |
73-
readonly DID_PATCHES_CHANGE=${{ steps.getOldPatchesHash.outputs.HASH != steps.getNewPatchesHash.outputs.HASH && 'true' || 'false' }}
74-
echo "DID_PATCHES_CHANGE=$DID_PATCHES_CHANGE" >> "$GITHUB_OUTPUT"
75-
if [[ "$DID_PATCHES_CHANGE" == 'true' ]]; then
76-
echo "::notice::Detected changes in patches (${{ steps.getOldPatchesHash.outputs.HASH }} -> ${{ steps.getNewPatchesHash.outputs.HASH }})"
67+
readonly DID_HYBRID_APP_PATCHES_CHANGE=${{ steps.getOldPatchesHash.outputs.HYBRID_APP_HASH != steps.getNewPatchesHash.outputs.HYBRID_APP_HASH && 'true' || 'false' }}
68+
readonly DID_STANDALONE_APP_PATCHES_CHANGE=${{ steps.getOldPatchesHash.outputs.STANDALONE_APP_HASH != steps.getNewPatchesHash.outputs.STANDALONE_APP_HASH && 'true' || 'false' }}
69+
echo "DID_HYBRID_APP_PATCHES_CHANGE=$DID_HYBRID_APP_PATCHES_CHANGE" >> "$GITHUB_OUTPUT"
70+
echo "DID_STANDALONE_APP_PATCHES_CHANGE=$DID_STANDALONE_APP_PATCHES_CHANGE" >> "$GITHUB_OUTPUT"
71+
72+
if [[ "$DID_HYBRID_APP_PATCHES_CHANGE" == 'true' ]]; then
73+
echo "::notice::Detected changes in HybridApp patches (${{ steps.getOldPatchesHash.outputs.HYBRID_APP_HASH }} -> ${{ steps.getNewPatchesHash.outputs.HYBRID_APP_HASH }})"
74+
fi
75+
76+
if [[ "$DID_STANDALONE_APP_PATCHES_CHANGE" == 'true' ]]; then
77+
echo "::notice::Detected changes in Standalone NewDot patches (${{ steps.getOldPatchesHash.outputs.STANDALONE_APP_HASH }} -> ${{ steps.getNewPatchesHash.outputs.STANDALONE_APP_HASH }})"
7778
fi
7879
79-
- name: Check if we should build and publish the package
80-
id: shouldPublish
80+
- name: Get artifact build targets
81+
id: getArtifactBuildTargets
8182
run: |
82-
if [[ '${{ steps.didVersionChange.outputs.DID_VERSION_CHANGE }}' == 'true' || '${{ steps.didPatchesChange.outputs.DID_PATCHES_CHANGE }}' == 'true' ]]; then
83-
echo "SHOULD_PUBLISH=true" >> "$GITHUB_OUTPUT"
84-
else
85-
echo "::notice::No relevant changes, skipping publishing a new React Native build"
86-
echo "SHOULD_PUBLISH=false" >> "$GITHUB_OUTPUT"
83+
# When there is a version change or standalone app patches change, we need to build for both hybrid and standalone
84+
if [[ '${{ steps.didVersionChange.outputs.DID_VERSION_CHANGE }}' == 'true' || '${{ steps.didPatchesChange.outputs.DID_STANDALONE_APP_PATCHES_CHANGE }}' == 'true' ]]; then
85+
echo "BUILD_TARGETS=[\"true\", \"false\"]" >> "$GITHUB_OUTPUT"
86+
elif [[ '${{ steps.didPatchesChange.outputs.DID_HYBRID_APP_PATCHES_CHANGE }}' == 'true' ]]; then
87+
echo "BUILD_TARGETS=[\"true\"]" >> "$GITHUB_OUTPUT"
8788
fi
8889
90+
buildAndPublishReactNativeArtifacts:
91+
name: Build and Publish React Native Artifacts
92+
runs-on: ${{ github.repository_owner == 'Expensify' && 'ubuntu-latest-xl' || 'ubuntu-latest' }}
93+
needs: verifyPatches
94+
if: needs.verifyPatches.outputs.build_targets != ''
95+
strategy:
96+
# Disable fail-fast to prevent cancelling both jobs when only one needs to be stopped due to concurrency limits
97+
fail-fast: false
98+
matrix:
99+
# Dynamically build the matrix based on the build targets
100+
is_hybrid: ${{ fromJSON(needs.verifyPatches.outputs.build_targets) }}
101+
concurrency:
102+
group: ${{ github.workflow }}-${{ github.job }}-${{ matrix.is_hybrid }}
103+
cancel-in-progress: true
104+
steps:
105+
- name: Checkout Code
106+
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
107+
with:
108+
submodules: ${{ matrix.is_hybrid }}
109+
token: ${{ secrets.OS_BOTIFY_TOKEN }}
110+
89111
- name: Setup Node
90-
if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }}
91112
uses: ./.github/actions/composite/setupNode
92113
with:
93114
IS_HYBRID_BUILD: ${{ matrix.is_hybrid }}
94115

95-
# v4
96116
- name: Setup Java
97-
if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }}
98117
uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12
99118
with:
100119
distribution: oracle
101120
java-version: 17
102121

103-
# v4
104122
- name: Setup Gradle
105-
if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }}
106123
uses: gradle/actions/setup-gradle@06832c7b30a0129d7fb559bcc6e43d26f6374244
107-
124+
108125
- name: Determine new patched RN version
109-
if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }}
110126
id: getNewPatchedVersion
111127
run: echo "NEW_PATCHED_VERSION=$(./.github/scripts/getNewPatchedRNVersion.sh)" >> "$GITHUB_OUTPUT"
112128
env:
113129
GITHUB_TOKEN: ${{ github.token }}
114130
IS_HYBRID_BUILD: ${{ matrix.is_hybrid }}
115131

116-
- name: Build and publish RN artifacts
117-
if: ${{ steps.shouldPublish.outputs.SHOULD_PUBLISH == 'true' }}
118-
working-directory: ${{ matrix.is_hybrid && 'Mobile-Expensify/Android' || 'android' }}
132+
- name: Build and publish React Native artifacts
133+
working-directory: ${{ matrix.is_hybrid == 'true' && 'Mobile-Expensify/Android' || 'android' }}
119134
run: |
120-
echo "Starting artifacts build for ${{ matrix.is_hybrid && 'HybridApp' || 'NewDot Standalone' }}"
135+
echo "Starting artifacts build for ${{ matrix.is_hybrid == 'true' && 'HybridApp' || 'NewDot Standalone' }}"
121136
echo "Version: ${{ env.PATCHED_VERSION }}"
122137
echo "Patches hash: ${{ env.PATCHES_HASH }}"
123138
export ORG_GRADLE_PROJECT_reactNativeArchitectures="armeabi-v7a,arm64-v8a,x86,x86_64"
@@ -128,7 +143,7 @@ jobs:
128143
GH_PUBLISH_TOKEN: ${{ github.token }}
129144
IS_HYBRID_BUILD: ${{ matrix.is_hybrid }}
130145
PATCHED_VERSION: ${{ steps.getNewPatchedVersion.outputs.NEW_PATCHED_VERSION }}
131-
PATCHES_HASH: ${{ steps.getNewPatchesHash.outputs.HASH }}
146+
PATCHES_HASH: ${{ matrix.is_hybrid == 'true' && needs.verifyPatches.outputs.hybrid_app_patches_hash || needs.verifyPatches.outputs.standalone_patches_hash }}
132147

133148
- name: Announce failed workflow in Slack
134149
if: ${{ failure() }}

.nvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
20.18.1
1+
20.19.1

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ android {
114114
minSdkVersion rootProject.ext.minSdkVersion
115115
targetSdkVersion rootProject.ext.targetSdkVersion
116116
multiDexEnabled rootProject.ext.multiDexEnabled
117-
versionCode 1009014605
118-
versionName "9.1.46-5"
117+
versionCode 1009014705
118+
versionName "9.1.47-5"
119119
// Supported language variants must be declared here to avoid from being removed during the compilation.
120120
// This also helps us to not include unnecessary language variants in the APK.
121121
resConfigs "en", "es"
Lines changed: 45 additions & 0 deletions
Loading

docs/articles/expensify-classic/expensify-card/Deactivate-or-cancel-an-Expensify-Card.md

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@ To cancel your Expensify Card:
2828

2929
# For Domain Admins
3030

31-
To deactivate an employee's Expensify Card:
32-
1. Hover over **Settings**, then click **Domains**.
33-
2. Click the name of the domain.
34-
3. Next to the card, click **Edit Limit**.
35-
4. Enable the **Custom Smart Limit** toggle to set a specific card limit. If not enabled, the card limit will match the group limit.
36-
5. Set the **Limit Amount** to $0. Adjusting the Smart Limit to $0 temporarily deactivates the card. The card will only be reactivated if the limit is increased.
37-
6. Click **Save**.
31+
To deactivate an employee’s Expensify Card:
32+
33+
1. Hover over **Settings**, then click **Domains**.
34+
2. Click the name of the domain.
35+
3. Next to the card, click **Edit Limit**.
36+
4. Enable the **Custom Smart Limit** toggle to set a specific card limit. If not enabled, the card limit will match the group limit.
37+
5. Set the **Limit Amount** to $0. Adjusting the Smart Limit to $0 temporarily deactivates the card. The card will only be reactivated if the limit is increased.
38+
6. Click **Save**.
39+
7. Instruct the cardholder to cancel their Expensify card by following the **[For Cardholders](https://help.expensify.com/articles/expensify-classic/expensify-card/Deactivate-or-cancel-an-Expensify-Card#for-cardholders)** section above.
3840

3941
**Important:** If you suspect fraudulent access to a Domain Admin account, contact Concierge Support via the in-app chat or email at [email protected]. If necessary, we can temporarily manually suspend cards outside of the Expensify Domain.
4042

docs/articles/expensify-classic/expensify-card/Dispute-Transaction.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ Follow the steps below to resolve your dispute quickly.
1717

1818
# How to Dispute a Transaction
1919

20-
If you find an incorrect charge on your Expensify Card:
20+
If you find an incorrect charge on your Expensify Card, follow the steps below. If you are a Domain Admin, follow the steps [here](https://help.expensify.com/articles/expensify-classic/expensify-card/Deactivate-or-cancel-an-Expensify-Card#for-domain-admins) before contacting Concierge Support.
2121

2222
1. If the charge is **fraudulent**, cancel your card right away (**Settings > Account > Wallet > Request a New Card**).
2323
2. Contact **Concierge Support**
2424
3. Provide details about the transaction, including:
25-
- Date and amount
26-
- Merchant name
27-
- Reason for the dispute
25+
- Date and amount
26+
- Merchant name
27+
- Reason for the dispute
2828
4. We’ll investigate the issue and file a dispute with our card processor on your behalf.
2929

3030
---

docs/articles/new-expensify/reports-and-expenses/Create-an-expense.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,17 @@ You can also forward receipts to [email protected] using your primary or se
124124

125125
{% include end-selector.html %}
126126

127+
## Bulk Upload Expenses from Desktop
128+
1. Check your files, they must be:
129+
- Under 10MB each
130+
- PDF or common image files
131+
- Under 30 files in total
132+
2. Select and drag your files into Expensify
133+
- **Scan Receipts** will add them as separate expenses
134+
- **Add Attachments** will attach them to a report or chat as supporting documentation
135+
3. Unsupported or oversized files will trigger a pop-up — choose to skip them or cancel entirely
136+
4. Add details such as coding for SmartScanning receipts, or confirm Attachments
137+
127138
# How to Delete an Expense
128139

129140
{% include selector.html values="desktop, mobile" %}

0 commit comments

Comments
 (0)