[NO QA] [Odometer] Build Odometer expense image capture flow#79576
Conversation
…se_image_capture_flow
Codecov Report❌ Looks like you've decreased code coverage for some files. Please write tests to increase, or at least maintain, the existing level of code coverage. See our documentation here for how to interpret this table.
|
|
Hey, I noticed you changed If you want to automatically generate translations for other locales, an Expensify employee will have to:
Alternatively, if you are an external contributor, you can run the translation script locally with your own OpenAI API key. To learn more, try running: npx ts-node ./scripts/generateTranslations.ts --helpTypically, you'd want to translate only what you changed by running |
|
This version is working, but the code needs to be cleaned up and some minor things have to be fixed. I am done for today but will work on this tomorrow with the aim of finishing it for initial review 🤞 |
…se_image_capture_flow
…se_image_capture_flow
|
So it took a few days for tomorrow to finally come 😅 |
…se_image_capture_flow
…se_image_capture_flow
…se_image_capture_flow
…se_image_capture_flow
This comment has been minimized.
This comment has been minimized.
|
@jakubkalinski0 I left some comments above. Could you take a look when you're available? |
…se_image_capture_flow
@DylanDylann Yeah, I wanted to split it into smaller PRs to allow for more thorough review. I also plan to do both native and mobile web separately as well as I assume native itself will be big enough on itself |
When it comes to the topic of not showing Discard Changes modal when switching to another distance request type you can actually read more about it in the discussion in the docs. It was decided back then to simply match the behavior of manual and map, but I personally agree that it would make sense to show this modal when image is given. I agree with Jules that we should revisit this discussion in the issue taking care of this modal |
@shawnborton does it look good enough for now? Screen.Recording.2026-02-04.at.23.05.52.mov |
|
@DylanDylann please review when you're available, we're getting close now 🤞 For any further UI issues I'll create issues separately as the feature is not visible to users. |
|
I will also fix the performance issue in a second. I want to make sure that revoking the blob url on image page works properly as it's being a bit of a headache at the moment |
It sounds like a good candidate for separating out from this PR perhaps? |
|
@Julesssss Actually I think that it pretty much works as it should now. We now reuse existing blob URLs ( If you have any comments (or you @DylanDylann), please let me know and if there are any more problems or doubts then we can revisit this in a separate issue. Screen.Recording.2026-02-05.at.02.03.34.mov |
| // Reset component state when switching away from the odometer tab | ||
| useEffect(() => { | ||
| if (!isFocused) { | ||
| if (isLoadingSelectedTab) { |
|
Yup, looking much better - thanks! |
Reviewer Checklist
Screenshots/VideosScreen.Recording.2026-02-05.at.12.38.39.mov |
|
The rest looks fine to me |
|
🚧 @Julesssss has triggered a test Expensify/App build. You can view the workflow run here. |
|
🧪🧪 Use the links below to test this adhoc build on Android, iOS, and Web. Happy testing! 🧪🧪
|
|
🚀 Deployed to staging by https://github.com/Julesssss in version: 9.3.13-1 🚀
|
|
🚀 Deployed to staging by https://github.com/Julesssss in version: 9.3.15-0 🚀
|
Explanation of Change
This PR implements the next part of the Odometer feature, aligned with Phase 1 tasks 1.D (capture start/end images) and 1.E (discard/clear on tab switch). This PR focuses on the web implementation of the image capture flow with image preview, native implementation and mobile web implementation to follow
ODOMETER_IMAGEscreen and route. We intentionally did not reuseIOURequestStepScanbecause that screen includes receipt‑specific behaviors (SmartScan, location prompts, receipt state logic). On web we follow an established patter of keeping a minimal upload UI that uses the existing drag‑and‑drop + file picker tooling on web.transaction.comment(odometerStartImage/odometerEndImage) rather than creating a separate draft store in Phase 1. This is intentional: draft storage is reserved for Phase 2 “Save for later”, while the transaction comment keeps the data tied to the in‑progress expense and survives navigation/confirmation without extra persistence logic.Fixed Issues
$ #77266
PROPOSAL: N/A
Tests
FABand pressTrack distanceOdometertab and verify the start/end reading inputs and image placeholders render.< buttonor outside of the RHP and verify if theDiscardChangesConfirmationis shownOffline tests
QA Steps
Same as Tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectioncanBeMissingparam foruseOnyxtoggleReportand notonIconClick)src/languages/*files and using the translation methodhttps://swmansion.slack.com/archives/C01GTK53T8Q/p1769726974775219
STYLE.md) were followedAvatar, I verified the components usingAvatarare working as expected)StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))npm run compress-svg)Avataris modified, I verified thatAvataris working as expected in all cases)Designlabel and/or tagged@Expensify/designso the design team can review the changes.ScrollViewcomponent to make it scrollable when more elements are added to the page.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps./** comment above it */thisproperly so there are no scoping issues (i.e. foronClick={this.submit}the methodthis.submitshould be bound tothisin the constructor)thisare necessary to be bound (i.e. avoidthis.submit = this.submit.bind(this);ifthis.submitis never passed to a component event handler likeonClick)Screenshots/Videos
MacOS: Chrome / Safari
Online:
online.mov
Offline:
offline.mov