Skip to content

Commit 6fe075c

Browse files
committed
Merge branch 'main' into perf/split-expense-report-list-item-row-defer-action-cell
2 parents eb8038d + b7c38b1 commit 6fe075c

247 files changed

Lines changed: 8137 additions & 3107 deletions

File tree

Some content is hidden

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

.github/actions/javascript/isDeployChecklistLocked/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11816,8 +11816,8 @@ async function generateDeployChecklistBodyAndAssignees({ tag, PRList, PRListMobi
1181611816
const check = (checked) => (checked ? 'x' : ' ');
1181711817
sections.push((0, dedent_1.default)(`
1181811818
**Deployer verifications:**
11819-
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${tag}/?project=app&environment=staging) for **this release version** and verified that this release does not introduce any new crashes. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
11820-
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${previousTag}/?project=app&environment=production) for **the previous release version** and verified that the release did not introduce any new crashes. Because mobile deploys use a phased rollout, completing this checklist will deploy the previous release version to 100% of users. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
11819+
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${tag}/?project=4510228107427840&environment=staging) for **this release version** and verified that this release does not introduce any new crashes. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
11820+
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${previousTag}/?project=4510228107427840&environment=production) for **the previous release version** and verified that the release did not introduce any new crashes. Because mobile deploys use a phased rollout, completing this checklist will deploy the previous release version to 100% of users. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
1182111821
- [${check(isGHStatusChecked)}] I checked [GitHub Status](https://www.githubstatus.com/) and verified there is no reported incident with Actions.
1182211822
`).trimEnd());
1182311823
// Footer

.github/libs/DeployChecklistUtils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ async function generateDeployChecklistBodyAndAssignees({
249249
sections.push(
250250
dedent(`
251251
**Deployer verifications:**
252-
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${tag}/?project=app&environment=staging) for **this release version** and verified that this release does not introduce any new crashes. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
253-
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${previousTag}/?project=app&environment=production) for **the previous release version** and verified that the release did not introduce any new crashes. Because mobile deploys use a phased rollout, completing this checklist will deploy the previous release version to 100% of users. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
252+
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${tag}/?project=4510228107427840&environment=staging) for **this release version** and verified that this release does not introduce any new crashes. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
253+
- [${check(isSentryChecked)}] I checked [Sentry](https://expensify.sentry.io/releases/new.expensify%40${previousTag}/?project=4510228107427840&environment=production) for **the previous release version** and verified that the release did not introduce any new crashes. Because mobile deploys use a phased rollout, completing this checklist will deploy the previous release version to 100% of users. More detailed instructions on this verification can be found [here](https://stackoverflowteams.com/c/expensify/questions/15095/15096).
254254
- [${check(isGHStatusChecked)}] I checked [GitHub Status](https://www.githubstatus.com/) and verified there is no reported incident with Actions.
255255
`).trimEnd(),
256256
);

Mobile-Expensify

android/app/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,8 @@ android {
111111
minSdkVersion rootProject.ext.minSdkVersion
112112
targetSdkVersion rootProject.ext.targetSdkVersion
113113
multiDexEnabled rootProject.ext.multiDexEnabled
114-
versionCode 1009036803
115-
versionName "9.3.68-3"
114+
versionCode 1009036903
115+
versionName "9.3.69-3"
116116
// Supported language variants must be declared here to avoid from being removed during the compilation.
117117
// This also helps us to not include unnecessary language variants in the APK.
118118
resConfigs "en", "es"

assets/fonts/NotoSansSC-Months.ttf

17.9 KB
Binary file not shown.

config/eslint/eslint.seatbelt.tsv

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@
277277
"../../src/libs/Navigation/AppNavigator/Navigators/RightModalNavigator.tsx" "no-restricted-syntax" 1
278278
"../../src/libs/Navigation/AppNavigator/Navigators/SearchFullscreenNavigator.tsx" "no-restricted-syntax" 1
279279
"../../src/libs/Navigation/AppNavigator/Navigators/TestToolsModalNavigator.tsx" "no-restricted-syntax" 1
280-
"../../src/libs/Navigation/AppNavigator/UserStatusHandler.tsx" "no-restricted-syntax" 1
281280
"../../src/libs/Navigation/helpers/createNormalizedConfigs.ts" "@typescript-eslint/no-deprecated/escape" 1
282281
"../../src/libs/Navigation/helpers/dismissModalAndOpenReportInInboxTab.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1
283282
"../../src/libs/Navigation/navigateAfterInteraction/index.ios.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1
@@ -316,7 +315,7 @@
316315
"../../src/libs/ReportUtils.ts" "rulesdir/no-onyx-connect" 17
317316
"../../src/libs/SearchUIUtils.ts" "@typescript-eslint/no-deprecated/getReportName" 1
318317
"../../src/libs/SearchUIUtils.ts" "@typescript-eslint/no-deprecated/getSearchReportName" 1
319-
"../../src/libs/SubscriptionUtils.ts" "rulesdir/no-onyx-connect" 2
318+
"../../src/libs/SubscriptionUtils.ts" "rulesdir/no-onyx-connect" 1
320319
"../../src/libs/TransactionUtils/index.ts" "@typescript-eslint/no-deprecated/translateLocal" 5
321320
"../../src/libs/UnreadIndicatorUpdater/index.ts" "no-restricted-syntax" 1
322321
"../../src/libs/Violations/ViolationsUtils.ts" "no-restricted-syntax" 2
@@ -489,7 +488,6 @@
489488
"../../src/pages/ScheduleCall/ScheduleCallPage.tsx" "react-hooks/preserve-manual-memoization" 1
490489
"../../src/pages/Search/SearchAdvancedFiltersPage/SearchFiltersCardPage.tsx" "react-hooks/set-state-in-effect" 1
491490
"../../src/pages/Search/SearchMoneyRequestReportPage.tsx" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1
492-
"../../src/pages/Search/SearchPage.tsx" "react-hooks/refs" 31
493491
"../../src/pages/Search/SearchPage.tsx" "react-hooks/set-state-in-effect" 1
494492
"../../src/pages/Search/SearchTransactionsChangeReport.tsx" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1
495493
"../../src/pages/Share/ShareRootPage.tsx" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1
@@ -532,6 +530,7 @@
532530
"../../src/pages/inbox/report/TripSummary.tsx" "rulesdir/no-default-id-values" 1
533531
"../../src/pages/inbox/report/UserTypingEventListener.tsx" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 4
534532
"../../src/pages/inbox/report/shouldUseEmojiPickerSelection/index.website.ts" "no-restricted-syntax" 1
533+
"../../src/pages/inbox/report/useReportActionsNewActionLiveTail.ts" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1
535534
"../../src/pages/inbox/report/withReportOrNotFound.tsx" "react-hooks/refs" 3
536535
"../../src/pages/inbox/sidebar/SidebarLinksData.tsx" "react-hooks/refs" 1
537536
"../../src/pages/iou/MoneyRequestAmountForm.tsx" "react-hooks/set-state-in-effect" 3
@@ -548,7 +547,7 @@
548547
"../../src/pages/iou/request/step/IOURequestStepDistance.tsx" "react-hooks/set-state-in-effect" 1
549548
"../../src/pages/iou/request/step/IOURequestStepDistanceGPS/BackgroundLocationPermissionsFlow/index.android.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 3
550549
"../../src/pages/iou/request/step/IOURequestStepDistanceGPS/BackgroundLocationPermissionsFlow/index.ios.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 2
551-
"../../src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSButtons/index.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 5
550+
"../../src/pages/iou/request/step/IOURequestStepDistanceGPS/GPSButtons/index.tsx" "@typescript-eslint/no-deprecated/ConfirmModal" 3
552551
"../../src/pages/iou/request/step/IOURequestStepDistanceMap.tsx" "react-hooks/set-state-in-effect" 1
553552
"../../src/pages/iou/request/step/IOURequestStepDistanceOdometer.tsx" "@typescript-eslint/no-deprecated/InteractionManager.runAfterInteractions" 1
554553
"../../src/pages/iou/request/step/IOURequestStepDistanceOdometer.tsx" "react-hooks/set-state-in-effect" 1

config/webpack/webpack.common.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {fileURLToPath} from 'url';
1414
import webpack from 'webpack';
1515
import type {Configuration, WebpackPluginInstance} from 'webpack';
1616
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
17+
import {GenerateSW} from 'workbox-webpack-plugin';
1718
// Storybook 10 loads TS files directly and requires .ts extension for ESM imports
1819
// @ts-expect-error -- Can't use .ts extensions without allowImportingTsExtensions in tsconfig
1920
// eslint-disable-next-line import/extensions
@@ -125,6 +126,40 @@ const getCommonConfiguration = ({file = '.env', platform = 'web'}: Environment):
125126
},
126127
plugins: [
127128
new CleanWebpackPlugin(),
129+
// Only emit the SW for non-development builds. In dev, webpack-dev-server's HMR
130+
// and the SW's caching behavior fight each other and confuse hot reloads.
131+
// Remove this guard locally if you want to actually exercise the SW.
132+
...(isDevelopment
133+
? []
134+
: [
135+
new GenerateSW({
136+
clientsClaim: true,
137+
skipWaiting: true,
138+
// Cap is generous on purpose: the vendor (~6.5 MiB), main (~5.5 MiB),
139+
// authScreens.prefetch (~6.3 MiB) chunks and canvaskit.wasm (~7.6 MiB) are
140+
// all critical for offline boot, so we precache the lot. Everything in the
141+
// App build is content-hashed, so growth here only costs first-install bytes.
142+
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024,
143+
// Single-page app: any unmatched navigation should serve the cached app shell.
144+
navigateFallback: '/index.html',
145+
// Don't fall back for asset-like or .well-known requests.
146+
navigateFallbackDenylist: [/^\/_/, /^\/\.well-known/, /\/[^/?]+\.[^/]+$/],
147+
runtimeCaching: [
148+
{
149+
// Same-origin user media (receipts, chat attachments) — cache opportunistically
150+
// so they're viewable on offline refresh. The function below is serialized into
151+
// the generated service worker, so it executes in the SW context where
152+
// `sameOrigin` is the appropriate Workbox match (no need to read `self.location`).
153+
urlPattern: ({sameOrigin, url, request}) => sameOrigin && (request.destination === 'image' || /\/(receipts|chat-attachments)\//.test(url.pathname)),
154+
handler: 'StaleWhileRevalidate',
155+
options: {
156+
cacheName: 'user-media',
157+
expiration: {maxEntries: 200, maxAgeSeconds: 7 * 24 * 60 * 60},
158+
},
159+
},
160+
],
161+
}),
162+
]),
128163
new HtmlWebpackPlugin({
129164
template: 'web/index.html',
130165
filename: 'index.html',

cspell.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@
800800
"Unmigrated",
801801
"unmuting",
802802
"unredacted",
803+
"unregisters",
803804
"unscrollable",
804805
"unsharing",
805806
"Unsharing",

docs/articles/new-expensify/expensify-card/Expensify-Card-Perks.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ From cash-back rewards to discounts on popular services, the Expensify Card offe
1414
## Cashback
1515
Get 1% cash back with every swipe — no minimums necessary — and 2% back if you spend $250k+/month across cards. This applies to US purchases only.
1616

17+
By default, cash back is applied toward your Expensify bill. Workspace Admins can change this in **Workspaces > [Workspace Name] > Expensify Card > Settings** by toggling **Apply cash back to my Expensify bill** off to send cash back to the settlement account instead.
18+
1719
## Discounts on Monthly Expensify Bill
1820
Get the Expensify Visa® Commercial Card and use it for at least half of your organization's monthly expenses to save 50% on your monthly Expensify bill.
1921

docs/articles/new-expensify/expensify-card/Set-Up-and-Manage-the-Expensify-Card.md

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,19 +84,48 @@ You can issue virtual or physical cards to employees:
8484
- Limit type
8585
- Card name
8686
- Deactivation
87-
4. To change the linked bank account or update settlement frequency, click **Settings**.
87+
4. To change the linked bank account, update settlement frequency, or manage cash back settings, click **Settings**.
8888

8989
![Click Expensify Card in the left menu to see a list of cards]({{site.url}}/assets/images/ExpensifyHelp-ExpensifyCard_05.png){:width="100%"}
9090

9191
![Click the card row to view the card details and make settings adjustments]({{site.url}}/assets/images/ExpensifyHelp-ExpensifyCard_06.png){:width="100%"}
9292

9393
![Click Settings to adjust the settlement account or frequency]({{site.url}}/assets/images/ExpensifyHelp-ExpensifyCard_08.png){:width="100%"}
9494

95+
---
96+
97+
## How to apply Expensify Card cash back to your Expensify bill
98+
99+
Workspace Admins with a US Expensify Card program can choose whether their Expensify Card cash back is applied toward their Expensify bill or sent to their settlement account. This setting is enabled by default.
100+
101+
1. From the navigation tabs (on the left on web, and at the bottom on mobile), go to **Workspaces > [Workspace Name] > Expensify Card**.
102+
2. Click **Settings**.
103+
3. Toggle **Apply cash back to my Expensify bill** on or off.
104+
105+
When enabled, cash back earned from the Expensify Card is automatically applied toward payment for your Expensify bill. When disabled, cash back is sent to your settlement account instead.
106+
107+
**Note:** This setting is only available for US card programs and is not shown for workspaces on an invoiced subscription.
108+
109+
---
110+
95111
If a Single-use card completes its first successful transaction, it automatically deactivates.
96112
If a card reaches its expiration date, it automatically deactivates and declines new transactions.
97113

98114
---
99115

116+
## How to export Expensify Card data as CSV
117+
118+
You can bulk-select cards and export their details to a CSV file for reporting or reconciliation.
119+
120+
1. From the navigation tabs (on the left on web, and at the bottom on mobile), select **Workspaces > [Workspace Name] > Expensify Card**.
121+
2. Select the checkboxes next to the cards you want to export. Use the checkbox in the header row to select all cards at once.
122+
3. Click the **selected** dropdown that appears.
123+
4. Select **Export as CSV**.
124+
125+
The downloaded CSV file includes the following columns for each selected card: email, name, last four digits, type (virtual or physical), limit type, and limit amount.
126+
127+
---
128+
100129
# How to freeze or unfreeze an Expensify Card
101130

102131
As a Workspace Admin, you can freeze or unfreeze any card in your workspace without needing to cancel or reissue it.

0 commit comments

Comments
 (0)