Skip to content

Conversation

@jakubkalinski0
Copy link
Contributor

@jakubkalinski0 jakubkalinski0 commented Jan 12, 2026

Explanation of Change

According to new contributing guide backTo is deprecated and shouldn't be added in newly added routes. For simpler implementation we initially added backTo to Odometer flow. This PR takes care of the complete removal of backTo from this newly added flow.

> [!WARNING]
> **Deprecated**: The `backTo` parameter is deprecated and should not be used in new implementations. Most problems that `backTo` solved can be resolved by adding one or more routes for a single screen. If you don't know how to solve your problem, contact someone from the navigation team. Old documentation on how to use `backTo` can be found below.

In the case of this flow the main issue when removing backTo is that we no longer posses information whether we are editing values from confirmation page or we are inputting the initial values for the first time on the first screen.

In order to differentiate those 2 situations the startOfFlow prop was added to the IOURequestStepDistanceOdometer function signature. We set this flag to true when we use it directly in TabSelector here:

{false && (
<TopTab.Screen name={CONST.TAB_REQUEST.DISTANCE_ODOMETER}>
{() => (
<TabScreenWithFocusTrapWrapper>
<IOURequestStepDistanceOdometer
route={route}
navigation={navigation}
/>
</TabScreenWithFocusTrapWrapper>
)}
</TopTab.Screen>
)}

This way we can easily define isEditingConfirmation as a simple check if the current state is different than startOfFlow and isEditing. Then we can also replace backTo by simply creating confirmationRoute from the data we have and navigate directly to it. This way we keep clean url without backTo throughout the whole Odometer flow.

It was also very important that DiscardChangesConfirmation is shown only when user tries to leave the odometer page in the following situation:

  1. user just started the expense creation
  2. there is any input in the start reading or end reading

Fixed Issues

$ #79036
PROPOSAL: N/A

Tests

Note:
When you want the Odometer to be show in the tab selector you need to first remove the false flag from here:

{false && (
<TopTab.Screen name={CONST.TAB_REQUEST.DISTANCE_ODOMETER}>
{() => (
<TabScreenWithFocusTrapWrapper>
<IOURequestStepDistanceOdometer
route={route}
navigation={navigation}
/>
</TabScreenWithFocusTrapWrapper>
)}
</TopTab.Screen>
)}

  1. Go to FAB
  2. Press Track distance
  3. Press Odometer
  4. Try to leave with empty values
  5. Verify that no DiscardChangesConfirmation modal is shown
  6. Go back to Odometer tab
  7. Fill start reading or end reading or both (doesn't matter - the behaviour should be the same in each case)
  8. Try to leave by clicking outside of RHP or by pressing < back button
  9. Verify that DiscardChangesConfirmation modal is shown
  10. Press Cancel on the DiscardChangesConfirmation modal and then Next
  11. Choose recipient
  12. When on confirmation page press Distance (you should be navigated to odometer page with readings fields filled)
  13. Make some changes and press < back button
  14. Verify that no DiscardChangesConfirmation modal is shown
  15. Once again press Distance
  16. Make some changes and press outside of the RHP
  17. Verify that no DiscardChangesConfirmation modal is shown and that RHP closes
  18. Now go through the odometer flow once again up to the point of confirmation page
  19. Once again press Distance
  20. Make some changes and press Save
  21. Verify that no DiscardChangesConfirmation modal is shown and that the total distance changed appropriately
  22. Now go to the just created expense and open it
  23. Press on Distance in order to edit the values
  24. Try to leave without changes (both pressing outside the RHP and < back button should work the same)
  25. Verify that no DiscardChangesConfirmation modal is shown and that the RHP closes correctly (i.e. the odometer page closes)
  26. Once again press Distance
  27. Make some changes
  28. Make some changes and press < back button or outside of RHP (both should behave the same)
  29. Verify that no DiscardChangesConfirmation modal is shown and that RHP closes properly
  30. Once again press Distance
  31. Make some changes and press Save
  32. Verify that no DiscardChangesConfirmation modal is shown and that the total distance changed appropriately
  33. Now press the FAB
  34. On the bottom of the popup menu you should see a quick action Track distance allowing you to create odometer expense to the same recipient to which you created the previous odometer expense
  35. Press that quick action
  36. Fill start reading or end reading or both (doesn't matter the behaviour should be the same in each case)
  37. Try to leave by clicking outside of RHP or by pressing < back button
  38. Verify that DiscardChangesConfirmation modal is shown
  39. Press Cancel on the DiscardChangesConfirmation modal and then Create expense
  40. Verify that no DiscardChangesConfirmation modal is shown; the RHP closes properly and the expense is correctly created
  41. Now go to any direct 1:1 chat
  42. Start the odometer expense flow from the chat
  43. Verify that DiscardChangesConfirmation behaves the same way as in steps 4 to 21
  • Verify that no errors appear in the JS console

Offline tests

Same as tests

QA Steps

// TODO: These must be filled out, or the issue title must include "[No QA]."

NO QA

  • Verify that no errors appear in the JS console

PR Author Checklist

  • I linked the correct issue in the ### Fixed Issues section above
  • I wrote clear testing steps that cover the changes made in this PR
    • I added steps for local testing in the Tests section
    • I added steps for the expected offline behavior in the Offline steps section
    • I added steps for Staging and/or Production testing in the QA steps section
    • I added steps to cover failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
    • I tested this PR with a High Traffic account against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
  • I included screenshots or videos for tests on all platforms
  • I ran the tests on all platforms & verified they passed on:
    • Android: Native
    • Android: mWeb Chrome
    • iOS: Native
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
  • I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I followed proper code patterns (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick)
    • 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
      • If any non-english text was added/modified, I used 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
    • 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.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I followed the guidelines as stated in the Review Guidelines
  • I tested other components that can be impacted by my changes (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar are working as expected)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • I verified that if a function's arguments changed that all usages have also been updated correctly
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG))
  • If new assets were added or existing ones were modified, I verified that:
    • The assets are optimized and compressed (for SVG files, run npm run compress-svg)
    • The assets load correctly across all supported platforms.
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • I added unit tests for any new feature or bug fix in this PR to help automatically prevent regressions in this user flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.

Screenshots/Videos

Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari

From steps 1 to 40:

1to40.mp4

From steps 41 to 43:

41to43.mov

@jakubkalinski0 jakubkalinski0 changed the title Removal of backTo from IOURequestStepDistanceOdometer [Odometer] Removal of backTo from Odometer flow Jan 12, 2026
@jakubkalinski0
Copy link
Contributor Author

For now there is some issue during the edition of an already existing expense so I am currently working on figuring that out

@codecov
Copy link

codecov bot commented Jan 12, 2026

Codecov Report

✅ Changes either increased or maintained existing code coverage, great job!

Files with missing lines Coverage Δ
.../components/MoneyRequestConfirmationListFooter.tsx 83.95% <ø> (ø)
...c/components/ReportActionItem/MoneyRequestView.tsx 0.25% <ø> (ø)
src/ROUTES.ts 12.23% <0.00%> (ø)
...ou/request/step/IOURequestStepDistanceOdometer.tsx 0.00% <0.00%> (ø)
... and 24 files with indirect coverage changes

@jakubkalinski0
Copy link
Contributor Author

For now there is some issue during the edition of an already existing expense so I am currently working on figuring that out

Fixed that. The issue that I am battling now is that when we are creating the expense from quick action then we should have the discardChangesConfirmation turned on but thats an issue since in quick action we skip everything else so the initial input is effectively the last screen so when we press create expense we run into the modal which tries to block navigation (in this case the navigation being closing the RHP)

Screen.Recording.2026-01-12.at.13.14.03.mov

@jakubkalinski0 jakubkalinski0 marked this pull request as ready for review January 12, 2026 20:32
@jakubkalinski0 jakubkalinski0 requested review from a team as code owners January 12, 2026 20:32
@melvin-bot melvin-bot bot requested review from DylanDylann and heyjennahay and removed request for a team January 12, 2026 20:32
@melvin-bot
Copy link

melvin-bot bot commented Jan 12, 2026

@DylanDylann Please copy/paste the Reviewer Checklist from here into a new comment on this PR and complete it. If you have the K2 extension, you can simply click: [this button]

@jakubkalinski0
Copy link
Contributor Author

There is a pretty big number of test steps but they are not that complicated so don't be scared by that 😅

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 146c2acd22

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@jakubkalinski0 jakubkalinski0 changed the title [Odometer] Removal of backTo from Odometer flow [No QA] [Odometer] Removal of backTo from Odometer flow Jan 12, 2026
report,
route: {
params: {action, iouType, reportID, transactionID, backTo, backToReport},
params: {action, iouType, reportID, transactionID, backToReport},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need backToReport? From my check, it always be undefined. Should we remove it?

Copy link
Contributor Author

@jakubkalinski0 jakubkalinski0 Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually it isn't always undefined. There are situations where it is needed. When a money request is launched directly from a report, that report ID is passed as backToReport. The route builders include it as an optional segment, and the submission handler uses it to navigate back to that report instead of defaulting to the active one. Without it, navigation would fall back to the active report and break that “return where you came from” behavior.

Screen.Recording.2026-01-13.at.11.07.45.mov

@DylanDylann
Copy link
Contributor

@jakubkalinski0 Thanks for the PR. Instead of adding a new parameter, could we derive this value from the current route?

In the creation flow:

  1. First Create (Using DistanceRequestStartPage route)
    - /create/submit/start/1/878852491103229/distance-new/distance-odometer
  2. Edit form confimation page (Using IOURequestStepDistanceOdometer route)
    - /create/submit/distance-odometer/1/878852491103229

@jakubkalinski0
Copy link
Contributor Author

@jakubkalinski0 Thanks for the PR. Instead of adding a new parameter, could we derive this value from the current route?

In the creation flow:

First Create (Using DistanceRequestStartPage route)

  • /create/submit/start/1/878852491103229/distance-new/distance-odometer
    Edit form confimation page (Using IOURequestStepDistanceOdometer route)
  • /create/submit/distance-odometer/1/878852491103229

Now that you mention it I think there is a chance that will work. I will look into it and let you know if it is possible to cover all required cases 🫡

const startOfFlow = routeName === SCREENS.MONEY_REQUEST.DISTANCE_CREATE;
const isEditing = action === CONST.IOU.ACTION.EDIT;
const isCreatingNewRequest = !(backTo ?? isEditing);
const isEditingConfirmation = !startOfFlow && !isEditing;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const isEditingConfirmation = !startOfFlow && !isEditing;
const isEditingConfirmation = routeName !== SCREENS.MONEY_REQUEST.DISTANCE_CREATE && !isEditing;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it like that to be more readable in the future for people without the context, but we can simplify it like that if you want to

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakubkalinski0 ok, so could you rename to isStartOfFlow ?

Copy link
Contributor Author

@jakubkalinski0 jakubkalinski0 Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DylanDylann I already changed it to your suggestion. I came to the conclusion that actually you can quite easily deduce what it means if you simply check what is that screen. Maybe we should add a one-line comment explaining whats the difference between isEditingConfirmation and isEditing because I can actually see that someone could find it confusing?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the comment seems like a good idea

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Julesssss Then I will add it right now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Julesssss Added ✅

});

if (shouldSkipConfirmation) {
setShouldEnableDiscardConfirmation(false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakubkalinski0 Why do we need to add this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the case of skipConfirmation flow we don't choose the recipient nor do we go to confirmation page and create the expense right away thus closing the RHP which DiscardChangesConfirmation tries to block so we have to turn it off right before submission. I described it here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please allow me more time to sleep on it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, no problemo

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakubkalinski0 could we remove setShouldEnableDiscardConfirmation and using directly

  <DiscardChangesConfirmation
                isEnabled={!isEditingConfirmation && !isEditing && !shouldSkipConfirmation}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually we can't do it this way. The DiscardChangesConfirmation has to be working in the case when shouldSkipConfirmation is True but has to be turned off just before submitting the expense in order to not show the discard modal when RHP closes on creation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean we could just turn it off completely in this case but then we would have inconsistent behaviour during the odometer expense creation flow depending where we start from which in my opinion would be pretty bad

@DylanDylann
Copy link
Contributor

@jakubkalinski0 Please also remove

https://github.com/DylanDylann/App/blob/93c20db001daff751d53bfb9b073dba227d564c9/src/libs/Navigation/types.ts#L1742-L1743


if (backToReport) {
Navigation.goBack(backTo);
if (isEditingConfirmation) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you change this condition?

Copy link
Contributor Author

@jakubkalinski0 jakubkalinski0 Jan 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's just incorrect. backToReport simply isn't indicative of editing from confirmation page thus the condition had to be changed

@DylanDylann
Copy link
Contributor

@jakubkalinski0 I still question why do we need to introduce isEnabled prop in DiscardChangesConfirmation. Should we use the same approach as other places instead introducing new way?

For example, please see isSaved flag in IOURequestStepMerchant

Screenshot 2026-01-13 at 19 18 18

@jakubkalinski0
Copy link
Contributor Author

jakubkalinski0 commented Jan 13, 2026

@jakubkalinski0 I still question why do we need to introduce isEnabled prop in DiscardChangesConfirmation. Should we use the same approach as other places instead introducing new way?

For example, please see isSaved flag in IOURequestStepMerchant

@DylanDylann I didn't notice this approach and it felt more natural to me to add this isEnabled approach. But to be honest it seems way better to not meddle with it especially if there is already another approach present in the codebase. I am a fan of your proposition and will switch the code right away!

@DylanDylann
Copy link
Contributor

For new features, I prefer to focus on the core logic of feature and limit refactoring anything. I think it's better to stick with the existing pattern for now and refactor in a separate PR later. This will save time and help us ship the feature faster. Thanks

@jakubkalinski0
Copy link
Contributor Author

@DylanDylann I think we will have to wait with this change of DiscardChangesConfirmation due to this PR thats currently introducing some changes to this component.

@jakubkalinski0
Copy link
Contributor Author

jakubkalinski0 commented Jan 13, 2026

@DylanDylann I would propose that we move on with this PR and resolve the DiscardChangesConfirmation issue in another PR. This way we wouldn't have to hold onto this PR until changes from the PR modifying DiscardChangesConfirmation is on Main.

@Julesssss What do you think? Maybe we should wait for the changes of DiscardChangesConfirmation from this PR to land on main and then adjust the code to Dylans proposition (which I personally like and agree with) and possible all the changes that come with the changes made to that component? If the changes are extensive enough we could even create a separate issue to take care of that

@Julesssss
Copy link
Contributor

would propose that we move on with this PR and resolve the DiscardChangesConfirmation issue in another PR.

I agree, especially as it's blocking the main feature work. DiscardChangesConfirmation PR also shouldn't be blocking our progress. I created a follow up issue here and added it to the tracker.

@DylanDylann could you complete your final review? I believe your latest comments have been addressed or responded to, but let me know if I missed something.

Julesssss
Julesssss previously approved these changes Jan 13, 2026
@DylanDylann
Copy link
Contributor

DylanDylann commented Jan 14, 2026

Reviewer Checklist

  • I have verified the author checklist is complete (all boxes are checked off).
  • I verified the correct issue is linked in the ### Fixed Issues section above
  • I verified testing steps are clear and they cover the changes made in this PR
    • I verified the steps for local testing are in the Tests section
    • I verified the steps for Staging and/or Production testing are in the QA steps section
    • I verified the steps cover any possible failure scenarios (i.e. verify an input displays the correct error message if the entered data is not correct)
    • I turned off my network connection and tested it while offline to ensure it matches the expected behavior (i.e. verify the default avatar icon is displayed if app is offline)
  • I checked that screenshots or videos are included for tests on all platforms
  • I included screenshots or videos for tests on all platforms
  • I verified that the composer does not automatically focus or open the keyboard on mobile unless explicitly intended. This includes checking that returning the app from the background does not unexpectedly open the keyboard.
  • I verified tests pass on all platforms & I tested again on:
    • Android: HybridApp
    • Android: mWeb Chrome
    • iOS: HybridApp
    • iOS: mWeb Safari
    • MacOS: Chrome / Safari
    • MacOS: Desktop
  • If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
  • I verified there are no new alerts related to the canBeMissing param for useOnyx
  • I verified proper code patterns were followed (see Reviewing the code)
    • I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. toggleReport and not onIconClick).
    • 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
    • I verified all numbers, amounts, dates and phone numbers shown in the product are using the localization methods
    • 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.
    • I verified the JSDocs style guidelines (in STYLE.md) were followed
  • If a new code pattern is added I verified it was agreed to be used by multiple Expensify engineers
  • I verified that this PR follows the guidelines as stated in the Review Guidelines
  • I verified other components that can be impacted by these changes have been tested, and I retested again (i.e. if the PR modifies a shared library or component like Avatar, I verified the components using Avatar have been tested & I retested again)
  • I verified all code is DRY (the PR doesn't include any logic written more than once, with the exception of tests)
  • I verified any variables that can be defined as constants (ie. in CONST.ts or at the top of the file that uses the constant) are defined as such
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately and each prop has a /** comment above it */
    • The file is named correctly
    • The component has a clear name that is non-ambiguous and the purpose of the component can be inferred from the name alone
    • The only data being stored in the state is data necessary for rendering and nothing else
    • For Class Components, any internal methods passed to components event handlers are bound to this properly so there are no scoping issues (i.e. for onClick={this.submit} the method this.submit should be bound to this in the constructor)
    • Any internal methods bound to this are necessary to be bound (i.e. avoid this.submit = this.submit.bind(this); if this.submit is never passed to a component event handler like onClick)
    • All JSX used for rendering exists in the render method
    • The component has the minimum amount of code necessary for its purpose, and it is broken down into smaller components in order to separate concerns and functions
  • If any new file was added I verified that:
    • The file has a description of what it does and/or why is needed at the top of the file if the code is not self explanatory
  • If a new CSS style is added I verified that:
    • A similar style doesn't already exist
    • The style can't be created with an existing StyleUtils function (i.e. StyleUtils.getBackgroundAndBorderStyle(theme.componentBG)
  • If the PR modifies code that runs when editing or sending messages, I tested and verified there is no unexpected behavior for all supported markdown - URLs, single line code, code blocks, quotes, headings, bold, strikethrough, and italic.
  • If the PR modifies a generic component, I tested and verified that those changes do not break usages of that component in the rest of the App (i.e. if a shared library or component like Avatar is modified, I verified that Avatar is working as expected in all cases)
  • If the PR modifies a component related to any of the existing Storybook stories, I tested and verified all stories for that component are still working as expected.
  • If the PR modifies a component or page that can be accessed by a direct deeplink, I verified that the code functions as expected when the deeplink is used - from a logged in and logged out account.
  • If the PR modifies the UI (e.g. new buttons, new UI components, changing the padding/spacing/sizing, moving components, etc) or modifies the form input styles:
    • I verified that all the inputs inside a form are aligned with each other.
    • I added Design label and/or tagged @Expensify/design so the design team can review the changes.
  • If a new page is added, I verified it's using the ScrollView component to make it scrollable when more elements are added to the page.
  • For any bug fix or new feature in this PR, I verified that sufficient unit tests are included to prevent regressions in this flow.
  • If the main branch was merged into this PR after a review, I tested again and verified the outcome was still expected according to the Test steps.
  • I have checked off every checkbox in the PR reviewer checklist, including those that don't apply to this PR.

Screenshots/Videos

Android: HybridApp
Screen.Recording.2026-01-14.at.10.51.45.mov
Android: mWeb Chrome
Screen.Recording.2026-01-14.at.10.50.16.mov
iOS: HybridApp
Screen.Recording.2026-01-14.at.10.50.59.mov
iOS: mWeb Safari
Screen.Recording.2026-01-14.at.10.49.12.mov
MacOS: Chrome / Safari
Screen.Recording.2026-01-14.at.10.46.42.mov

@melvin-bot melvin-bot bot requested a review from Julesssss January 14, 2026 03:55
@DylanDylann
Copy link
Contributor

@Julesssss All yours

@Julesssss Julesssss merged commit bc128a6 into Expensify:main Jan 14, 2026
31 of 33 checks passed
@OSBotify
Copy link
Contributor

✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release.

@OSBotify
Copy link
Contributor

🚀 Deployed to staging by https://github.com/Julesssss in version: 9.3.2-0 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 cancelled 🔪

@OSBotify
Copy link
Contributor

🚀 Deployed to production by https://github.com/francoisl in version: 9.3.3-8 🚀

platform result
🕸 web 🕸 success ✅
🤖 android 🤖 success ✅
🍎 iOS 🍎 success ✅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants