Migrate per diem subrate step to dynamic routes (#83850 part 3) - #98629
Migrate per diem subrate step to dynamic routes (#83850 part 3)#98629suneox wants to merge 6 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 14e4d0067f
ℹ️ 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".
14e4d00 to
4b3c9c1
Compare
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
JmillsExpensify
left a comment
There was a problem hiding this comment.
No product review required.
|
Tag me when it's ready |
…BRATE_EDIT routes with the and dynamic suffixes, following parts 1 (destination) and 2 (time). - The wizard suffix is stacked on the dynamic time route, the edit suffix on the confirmation route, so both drop and derive their back path from the URL via useDynamicBackPath. - Rename IOURequestStepSubrate to DynamicIOURequestStepSubrate and switch the edit-mode check from to the route name. - PerDiemFields no longer needs action/iouType/reportID now that all three per diem fields navigate through dynamic routes. - Add OldRoutes redirects (including the legacy backToReport variant) plus unit tests.
4b3c9c1 to
ee9023a
Compare
It's ready |
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeiOS: HybridAppiOS: mWeb SafariMacOS: Chrome / Safari |
Screen.Recording.2026-08-17.at.15.32.06.movScreen.Recording.2026-08-17.at.15.35.18.movBUG: Not Found appears when opening the Per Diem subrate |
@huult Could you check your build and confirm if the bundle is ready? I haven't encountered any bugs. CleanShot.2026-08-17.at.15.37.57.1.mp4 |
Screen.Recording.2026-08-17.at.15.44.29.mov@suneox I’m still able to reproduce this issue |
|
@huult The issue has been fixed for both single and multiple workspaces with per-diem enabled CleanShot.2026-08-17.at.17.26.10.1.mp4 |
Explanation of Change
This is part 3 of migrating the per diem money request steps to dynamic URL navigation (after part 1 — destination and part 2 — time). It replaces the static
MONEY_REQUEST_STEP_SUBRATEandMONEY_REQUEST_STEP_SUBRATE_EDITroutes with theper-diem-subrate/:pageIndexandper-diem-subrate-edit/:pageIndexdynamic suffixes. The wizard suffix is stacked on the dynamic time route (entryScreens: [MONEY_REQUEST.DYNAMIC_STEP_TIME]) and the edit suffix on the confirmation route (entryScreens: [MONEY_REQUEST.STEP_CONFIRMATION]), so both dropbackToand derive their back path from the current URL throughuseDynamicBackPath; the page distinguishes edit mode by route name instead of bybackTo.IOURequestStepSubrateis renamed toDynamicIOURequestStepSubrate, andPerDiemFieldsno longer needs theaction/iouType/reportIDprops now that all three per diem fields navigate through dynamic routes. LegacysubrateURLs (including the optionalbackToReportsegment and theeditvariant) are redirected throughOldRoutes, with unit tests covering both the redirect shape and the no-false-positive case for the already-migrated paths.Fixed Issues
$ #83850
PROPOSAL:
Tests
DYNAMIC_ROUTES.MONEY_REQUEST_STEP_SUBRATE — wizard subrate step
Case 1.1 — Time → Subrate forward (multi-policy base)
Target:
src/pages/iou/request/step/DynamicIOURequestStepTime.tsx(updateTime)Precondition: the account has 2 or more workspaces with per diem enabled (so the flow goes through the workspace selector → Destination → Time).
Steps:
Expected: the Subrate step opens (Subrate picker + Quantity input), the URL ends with
/per-diem-time/per-diem-subrate/0, and the header title is the tab title (not "Subrate").Case 1.2 — Time → Subrate forward (single-policy base, opened from the start page)
Precondition: the account has exactly one workspace with per diem enabled (Destination renders inline on the start page, so Time is built on the
startbase).Steps:
Expected: Subrate opens, URL is
/create/submit/start/<txn>/<rpt>/per-diem-time/per-diem-subrate/0(noper-diem-destinationsegment).Case 1.3 — Subrate back → Time
Target:
src/pages/iou/request/step/DynamicIOURequestStepSubrate.tsxSteps:
Expected: back on the Time step; exactly the
/per-diem-subrate/0segment is removed from the URL and the base is unchanged. No/not-found.Case 1.4 — Subrate submit → Confirmation
Steps:
2) → Save.Expected: the Confirmation step opens (still a static route) and the subrate shows up in the per diem fields.
Case 1.5 — Confirmation back → Subrate
Target:
src/pages/iou/request/step/IOURequestStepConfirmation.tsx(navigateBack)Steps:
Expected: back on Subrate (the route is already on the stack, so it pops to it). No
/not-foundand no duplicated suffix.Case 1.6 — Refresh while on Subrate
Steps:
Expected: still on the Subrate step and the stack is restored (Back goes to Time).
Case 1.7 — Legacy deep link redirect (pageIndex preserved)
Target:
src/libs/Navigation/linkingConfig/OldRoutes.tsSteps:
/create/submit/subrate/<txn>/<rpt>/0.Expected: redirected to⚠️
/create/submit/start/<txn>/<rpt>/per-diem-time/per-diem-subrate/0.getMatchingNewRoutere-appends the original query, so a legacy URL that still carries?backTo=keeps it on the redirected route (and on its base route). This matches the destination and time redirects already onmain; no call site emits that query anymore.Case 1.8 — Legacy deep link with a
backToReportsegmentSteps:
/create/submit/subrate/<txn>/<rpt>/<backToReportID>/2.Expected: redirected to
/create/submit/start/<txn>/<rpt>/<backToReportID>/per-diem-time/per-diem-subrate/2.Case 1.9 — Offline forward/back
Steps:
Expected: navigation still works offline and the offline indicator shows.
DYNAMIC_ROUTES.MONEY_REQUEST_STEP_SUBRATE_EDIT — edit a subrate from Confirmation
Case 2.1 — Confirmation → edit Subrate (correct index)
Target:
src/components/MoneyRequestConfirmationList/sections/PerDiemFields.tsxPrecondition: a per diem Confirmation with at least one subrate (run case 1.4 first).
Steps:
Expected: the Subrate page opens in edit mode, header title "Subrate", URL
/create/submit/confirmation/<txn>/<rpt>/per-diem-subrate-edit/0, and the picker/quantity are prefilled with subrate 0.Case 2.2 — Edit save → back on Confirmation
Steps:
2→3) → Save.Expected: back on Confirmation (the
/per-diem-subrate-edit/0segment is removed) and the field shows the new quantity.Case 2.3 — Edit back without saving
Steps:
Expected: back on Confirmation with the subrate unchanged.
Case 2.4 — Edit the second subrate (pageIndex > 0)
Precondition: the rate has 2 or more subrates and the expense already has 2 subrates.
Steps:
Expected: URL
.../per-diem-subrate-edit/1and subrate index 1 is shown (not index 0).Case 2.5 — Delete a subrate (three-dots menu)
Steps:
Expected: the subrate is deleted and the app goes back to Confirmation with the remaining subrates listed.
Case 2.6 — Legacy edit deep link redirect
Steps:
/create/submit/subrate/<txn>/<rpt>/edit/2.Expected: redirected to
/create/submit/confirmation/<txn>/<rpt>/per-diem-subrate-edit/2.Regression
per-diem-destination-edit) —PerDiemFieldsprops changed.per-diem-time-edit).per-diem-destination.Offline tests
QA Steps
Test case 1: Create a per diem expense and reach the subrate step
/per-diem-time/per-diem-subrate/0./per-diem-subrate/0part removed from the URL.Test case 2: Edit a subrate from the confirmation page
/per-diem-subrate-edit/0.PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectionAvatar, 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.mainbranch was merged into this PR after a review, I tested again and verified the outcome was still expected according to theTeststeps.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari
CleanShot.2026-08-17.at.14.09.11.1.mp4
+++ Case 1.1 — Time → Subrate forward (multi-policy base)
+++
+++ Case 1.2 — Time → Subrate forward (single-policy base)
+++
+++ Case 1.3 — Subrate back → Time
+++
+++ Case 1.4 — Subrate submit → Confirmation
+++
+++ Case 1.5 — Confirmation back → Subrate
+++
+++ Case 1.6 — Refresh while on Subrate
+++
+++ Case 1.7 — Legacy deep link redirect
+++
+++ Case 1.8 — Legacy deep link with backToReport
Not support create deeplink with subrate
+++
+++ Case 1.9 — Offline forward/back
+++
+++ Case 2.1 — Confirmation → edit Subrate
+++
+++ Case 2.2 — Edit save → back on Confirmation
+++
+++ Case 2.3 — Edit back without saving
+++
+++ Case 2.4 — Edit the second subrate
+++
+++ Case 2.5 — Delete a subrate
+++
+++ Case 2.6 — Legacy edit deep link redirect
Not support create via deep link with edit subrate
+++
+++ Regression
+++