Skip to content

Migrate Money Request (Part 1) routes to dynamic URL navigation - #96900

Merged
mjasikowski merged 3 commits into
Expensify:mainfrom
suneox:83849-migrate-money-request-part-1-suneox
Jul 27, 2026
Merged

mjasikowski merged 3 commits into
Expensify:mainfrom
suneox:83849-migrate-money-request-part-1-suneox

Conversation

@suneox

@suneox suneox commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Explanation of Change

Migrate 3 RHP routes in the new-task / money-request flow to dynamic URL navigation (feature #73825), removing their backTo params:

  • NEW_TASK_SHARE_DESTINATIONtask-share-destination (entry screen: NEW_TASK.DYNAMIC_ROOT)
  • MONEY_REQUEST_STEP_SEND_FROMsend-from (entry screen: MONEY_REQUEST.STEP_CONFIRMATION)
  • MONEY_REQUEST_STEP_COMPANY_INFOcompany-info (entry screen: MONEY_REQUEST.STEP_CONFIRMATION)

Screens are renamed to Dynamic* and wired through DYNAMIC_ROUTES + linkingConfig + ModalStackNavigators + types. Call sites now use createDynamicRoute(...) and back navigation uses useDynamicBackPath(...). OldRoutes redirects map the legacy paths to the new nested routes — the invoice send-from / company-info redirects include the dynamic suffix so a legacy deep-link restores the actual substep. MONEY_REQUEST_STEP_CONFIRMATION and MONEY_REQUEST_STEP_AMOUNT are not migratable (multiple required path params) and remain static.

Fixed Issues

$ #83849
PROPOSAL:

Tests

DYNAMIC_ROUTES.NEW_TASK_SHARE_DESTINATION — Share Destination from Confirm Task
Case 1.1 — Entry: Confirm task → tap Share → opens Share Destination (dynamic)

Target: DynamicNewTaskPage.tsxNavigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.NEW_TASK_SHARE_DESTINATION.path)).

Precondition: logged in; workspace chat <R>; clean task draft; on Confirm task (task-confirm) without parentReportID (Share is interactive).

Steps:

  1. Open the app → log in.
  2. LHN → open workspace chat <R>.
  3. Compose +Assign task → enter TitleContinue/Next (Confirm task).
  4. Verify URL has suffix task-confirm (e.g. /r/<R>/task-confirm or /task-details/task-confirm).
  5. Tap the Share row (required).
  6. Verify the Share Destination page opens (report search list).
  7. Verify URL = confirm base + /task-share-destination (e.g. …/task-confirm/task-share-destination) — not absolute /new/task/share-destination.
  8. Tap Back (header) → verify return to Confirm task; URL no longer has task-share-destination.
    Expected: Dynamic entry opens the correct page; new URL shape is correct; Back strips the suffix to confirm. No console errors.
Case 1.2 — Select destination → goBack to confirm (selection kept)

Target: DynamicTaskShareDestinationSelectorModal.tsxselectReportHandlerNavigation.goBack(backPath).

Precondition: on Share Destination (Case 1.1).

Steps:

  1. Search / select a report as share destination.
  2. Verify return to Confirm task; Share row shows the selected destination name.
  3. Verify URL no longer has task-share-destination.
    Expected: Selection uses goBack(backPath) (not bare goBack()); confirm context is preserved.
Case 1.3 — Refresh / deeplink on new URL …/task-share-destination

Precondition: on Share Destination; copy the full URL.

Steps:

  1. Reload the page (Web) or reopen the same URL.
  2. Verify Share Destination is restored (no 404 / no Home fallback).
  3. Paste the URL in a new tab → Enter → verify it opens correctly.
  4. Tap Back → return to Confirm; suffix stripped.
    Expected: Refresh + deeplink restore the correct stack (confirm underneath + share on top).
Case 1.4 — Old URL /new/task/share-destination (backward-compat)

Target: OldRoutes.ts'/new/task/share-destination': '/task-details/task-confirm/task-share-destination'.

Precondition: logged in.

Steps:

  1. Paste https://dev.new.expensify.com:8082/new/task/share-destination → Enter.
  2. Verify redirect/open equivalent /task-details/task-confirm/task-share-destination (Share Destination on confirm stack).
    Expected: Old bookmark resolves to the full new URL including suffix.
DYNAMIC_ROUTES.MONEY_REQUEST_STEP_SEND_FROM — Send from (invoice confirmation)
Case 2.1 — Entry: Invoice confirmation → tap Send from → opens Send from (dynamic)

Target: InvoiceSenderField.tsxNavigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MONEY_REQUEST_STEP_SEND_FROM.path)).

Precondition: admin workspace <W> with areInvoicesEnabled; invoice created from FAB / global create (isFromGlobalCreate); participant is not an invoice room; user has ≥1 admin workspace that can send invoices → canUpdateSenderWorkspace === true (Send from chevron visible).

Steps:

  1. Open the app → log in as an admin with Invoices.
  2. Tap FAB (+)Send Invoice.
  3. Enter amount → select a participant (not an invoice room) → reach confirmation.
  4. Verify the Send from (workspace) row is interactive / has a chevron.
  5. Tap Send from.
  6. Verify the Send from / workspace picker page opens.
  7. Verify URL = /create/invoice/confirmation/<T>/<R>/send-from (confirmation + suffix) — not /create/invoice/from/<T>/<R>.
  8. Tap Back → verify return to confirmation; URL no longer has /send-from.
    Expected: Dynamic entry is correct; new URL shape is correct; Back strips the suffix. No console errors.
Case 2.2 — Select workspace → return to confirmation

Target: DynamicIOURequestStepSendFrom.tsxnavigateBack / selectWorkspace.

Precondition: on Send from (Case 2.1); ≥2 workspaces that can send invoices (so a change is possible).

Steps:

  1. Select a different workspace in the list.
  2. Verify return to confirmation; Send from shows the new workspace.
  3. Verify URL no longer has /send-from.
    Expected: Selection + back via useDynamicBackPath; confirmation context preserved.
Case 2.3 — Refresh / deeplink on new URL …/confirmation/…/send-from

Precondition: on Send from; copy the URL.

Steps:

  1. Reload / reopen the URL.
  2. Verify Send from restores on top of the confirmation stack (no 404 / Home).
  3. Tap Back → confirmation; suffix stripped.
    Expected: Refresh + deeplink restore correctly.
Case 2.4 — Old URL /create/invoice/from/<T>/<R> (backward-compat)

Target: OldRoutes.ts'/create/*/from/*/*': '/create/$1/confirmation/$2/$3/send-from' (includes suffix → restores substep).

Precondition: logged in; valid <T> / <R> from Case 2.1 (or any path-shaped txn/report IDs).

Steps:

  1. Paste old URL /create/invoice/from/<T>/<R> (no query) → Enter.
  2. Expected: redirect → /create/invoice/confirmation/<T>/<R>/send-from (opens Send from on the confirmation stack).
  3. Tap Back → confirmation; suffix stripped.
    Expected: old deeplink restores the Send from substep. (Query variant ?backTo=… is not supported for suffixed redirects; not tested.)
DYNAMIC_ROUTES.MONEY_REQUEST_STEP_COMPANY_INFO — Company info (invoice confirm short-circuit)
Case 3.1 — Entry: Confirm invoice (no company info yet) → opens Company info (dynamic)

Target: confirmAction.tsNavigation.navigate(createDynamicRoute(DYNAMIC_ROUTES.MONEY_REQUEST_STEP_COMPANY_INFO.path)). Guard: iouType === INVOICE && !hasInvoicingDetails(policy) && transactionID && !routeError.

Precondition: sender workspace has no invoice.companyName + invoice.companyWebsite; on invoice confirmation (FAB → Send Invoice → …).

Steps:

  1. Open the app → log in; ensure sender workspace has no Company name/website (Workspace settings → Invoices).
  2. FABSend Invoice → amount → participant → confirmation.
  3. Tap the confirm / send invoice button.
  4. Verify the Company info page opens (company name / website form).
  5. Verify URL = /create/invoice/confirmation/<T>/<R>/company-info.
  6. Tap Back → verify return to confirmation; URL no longer has /company-info.
    Expected: Short-circuit navigate uses the dynamic suffix; Back strips correctly. No console errors.
Case 3.2 — Refresh / deeplink on new URL …/company-info

Precondition: on Company info; copy the URL.

Steps:

  1. Reload / reopen the URL.
  2. Verify Company info restores.
  3. Tap Back → confirmation; suffix stripped.
    Expected: Refresh + deeplink restore correctly.
Case 3.3 — Old URL /create/invoice/company-info/<T>/<R> (backward-compat)

Target: OldRoutes.ts'/create/*/company-info/*/*': '/create/$1/confirmation/$2/$3/company-info' (includes suffix → restores substep).

Precondition: logged in.

Steps:

  1. Paste old URL (no query) → Enter.
  2. Expected: redirect → /create/invoice/confirmation/<T>/<R>/company-info (opens Company info).
  3. Tap Back → confirmation; suffix stripped.
    Expected: old deeplink restores Company info. (Query variant not supported for suffixed redirects; not tested.)
  • Verify that no errors appear in the JS console

Offline tests

  • Same as tests — navigation refactor, offline behavior is unchanged.

QA Steps

#### Test case 1: New Task — Share destination opens as a nested route (Only happen from FAB with isValidReport=false base on current code)

  1. Log in and open a workspace chat from the left-hand panel.
  2. Tap the compose +Assign task, enter a Title, then tap Continue.
  3. On the Confirm task screen, tap the Share row.
  4. Verify the Share destination page opens (a searchable report list).
  5. Verify the URL ends with /task-share-destination (e.g. …/task-confirm/task-share-destination) — not the old /new/task/share-destination.
  6. Tap Back and verify you return to the Confirm task screen (the URL no longer contains task-share-destination).

Test case 2: Invoice — Send from opens as a nested route

  1. Log in as an admin on a workspace with Invoices enabled.
  2. Tap the + (FAB)Send invoice.
  3. Enter an amount, select a participant from contact section, and continue to the confirmation screen.
  4. Tap the Send from (workspace) row.
  5. Verify the Send from workspace picker opens.
  6. Verify the URL is /create/invoice/confirmation/<T>/<R>/send-from — not the old /create/invoice/from/<T>/<R>.
  7. Tap Back and verify you return to the confirmation screen (the URL no longer contains /send-from).

Test case 3: Invoice without company info — Company info opens as a nested route

  1. Log in as an admin whose invoice workspace has no company name / website set.
  2. Tap the + (FAB)Send invoice, enter an amount, select a ws participant, and continue to the confirmation screen.
  3. Tap the confirm / send button.
  4. Verify the Company info page opens (company name / website form).
  5. Verify the URL is /create/invoice/confirmation/<T>/<R>/company-info.
  6. Tap Back and verify you return to the confirmation screen (the URL no longer contains /company-info).
  • 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 followed proper code patterns (see Reviewing the code)
    • 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 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)
  • 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)
  • 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.
  • 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
Case 1.1 — Entry: Confirm task → tap Share → opens Share Destination (dynamic) 1 1-1-before-task-confirm-share-row 1 1-2-entry-share-destination 1 1-3-after-back-task-confirm-no-suffix
Case 1.2 — Select destination → goBack to confirm (selection kept) 1 2-2-entry-share-destination-selector-open 1 2-3-after-back-confirm-new-destination-selected
Case 1.3 — Refresh / deeplink on new URL …/task-share-destination 1 3-1-before-share-destination-pre-reload 1 3-2-entry-share-destination-after-reload
Case 1.4 — Old URL /new/task/share-destination (backward-compat) 1 4-1-before-oldurl-new-task-share-destination 1 4-2-entry-redirected-task-share-destination
Case 2.1 — Entry: Invoice confirmation → tap Send from → opens Send from (dynamic) 2 1-1-before-invoice-confirmation-send-from-interactive 2 1-2-entry-send-from-dynamic-route 2 1-3-after-back-confirm-suffix-stripped
Case 2.2 — Select workspace → return to confirmation 2 2-1-before-send-from-selector-two-workspaces 2 2-3-after-back-confirm-ws002-selected
Case 2.3 — Refresh / deeplink on new URL …/confirmation/…/send-from 2 3-1-before-send-from-pre-reload 2 3-2-entry-send-from-after-reload
Case 2.4 — Old URL /create/invoice/from/<T>/<R> (backward-compat) 2 4-1-before-oldurl-create-invoice-from 2 4-2-entry-redirected-confirmation-send-from
Case 3.1 — Entry: Confirm invoice (no company info yet) → opens Company info (dynamic) 3 1-1-before-invoice-confirm-no-company-info 3 1-2-entry-company-info-dynamic-route
Case 3.2 — Refresh / deeplink on new URL …/company-info 3 2-1-before-company-info-pre-reload 3 2-2-entry-company-info-after-reload
Case 3.3 — Old URL /create/invoice/company-info/<T>/<R> (backward-compat) 3 3-1-before-oldurl-create-invoice-company-info 3 3-2-entry-redirected-confirmation-company-info

Migrate the 3 migratable routes from Expensify#83849 to dynamic routes, removing
their backTo params:
- NEW_TASK_SHARE_DESTINATION -> task-share-destination (entry: DYNAMIC_ROOT)
- MONEY_REQUEST_STEP_SEND_FROM -> send-from (entry: STEP_CONFIRMATION)
- MONEY_REQUEST_STEP_COMPANY_INFO -> company-info (entry: STEP_CONFIRMATION)

Swap SCREENS keys to DYNAMIC_*, rename pages to Dynamic*, wire linkingConfig
+ ModalStack + types, replace navigate call sites with createDynamicRoute,
and use useDynamicBackPath for back navigation.

OldRoutes redirects include the dynamic suffix so a legacy deep-link restores
the actual substep (not just the confirmation entry). Query preservation is
not guaranteed for these suffixed redirects due to the trailing-wildcard
matcher; no call site produces these legacy paths with a query anymore.

CONFIRMATION and AMOUNT are not migratable (multiple path params) and are
left as static routes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@suneox
suneox force-pushed the 83849-migrate-money-request-part-1-suneox branch from fbb9c20 to 608f613 Compare July 23, 2026 18:15
@codecov

codecov Bot commented Jul 23, 2026

Copy link
Copy Markdown

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.

Files with missing lines Coverage Δ
src/ROUTES.ts 21.69% <ø> (-0.04%) ⬇️
src/SCREENS.ts 100.00% <ø> (ø)
src/components/MoneyRequestConfirmationList.tsx 94.69% <ø> (ø)
...ents/MoneyRequestConfirmationList/confirmAction.ts 100.00% <100.00%> (ø)
...stConfirmationList/sections/InvoiceSenderField.tsx 92.30% <100.00%> (ø)
...mationListFooter/sections/InvoiceSenderSection.tsx 100.00% <100.00%> (ø)
src/libs/Navigation/linkingConfig/OldRoutes.ts 100.00% <ø> (ø)
src/libs/Navigation/linkingConfig/config.ts 66.66% <ø> (ø)
...iou/request/step/withFullTransactionOrNotFound.tsx 96.15% <ø> (ø)
.../iou/request/step/withWritableReportOrNotFound.tsx 83.87% <ø> (ø)
... and 5 more
... and 12 files with indirect coverage changes

@suneox
suneox marked this pull request as ready for review July 24, 2026 06:24
@suneox
suneox requested review from a team as code owners July 24, 2026 06:24
@melvin-bot
melvin-bot Bot requested a review from huult July 24, 2026 06:24
@melvin-bot

melvin-bot Bot commented Jul 24, 2026

Copy link
Copy Markdown

@huult 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]

@melvin-bot
melvin-bot Bot requested review from heyjennahay and removed request for a team July 24, 2026 06:24

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

Copy link
Copy Markdown

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: 608f613b0a

ℹ️ 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".

Comment on lines +78 to +79
'/create/*/from/*/*': '/create/$1/confirmation/$2/$3/send-from',
'/create/*/company-info/*/*': '/create/$1/confirmation/$2/$3/company-info',

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve queries when rewriting legacy invoice substeps

These mappings append the new dynamic suffix after $3, but getMatchingNewRoute compiles a * at the end of a pattern as (.*), so $3 also captures any existing query string. The legacy route builders used to add ?backTo=..., so refreshing or opening an old URL like /create/invoice/from/123/456?backTo=/home redirects to /create/invoice/confirmation/123/456?backTo=/home/send-from; the dynamic suffix is then inside the query, and the app parses the confirmation page instead of the Send from/Company info substep. Please split/preserve the query before appending the suffix, or adjust the matcher, for these invoice substep redirects.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@suneox could you check this?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This PR removes the legacy route builders that were the only source of a ?backTo=, this pattern is a common for migrate route

@huult

huult commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

Reviewing...

@huult

huult commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

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
  • 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 proper code patterns were followed (see Reviewing the code)
    • 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 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)
  • 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)
  • If a new component is created I verified that:
    • A similar component doesn't exist in the codebase
    • All props are defined accurately
    • 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
    • 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 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.
  • 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
Android: mWeb Chrome
iOS: HybridApp
iOS: mWeb Safari
MacOS: Chrome / Safari
Screen.Recording.2026-07-25.at.14.58.24.mov

Comment thread config/eslint/eslint.seatbelt.tsv Outdated

@huult huult left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM.

@melvin-bot
melvin-bot Bot requested a review from mjasikowski July 27, 2026 01:16
@mjasikowski
mjasikowski merged commit b20d1c0 into Expensify:main Jul 27, 2026
36 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🚧 mjasikowski has triggered a test Expensify/App build. You can view the workflow run here.

@OSBotify

Copy link
Copy Markdown
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
Copy Markdown
Contributor

🚀 Deployed to staging by https://github.com/mjasikowski in version: 9.4.45-0 🚀

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

@MelvinBot

Copy link
Copy Markdown
Contributor

🤖 I reviewed the changes in this PR against the help site content under docs/articles.

No help site changes are required, so I did not create a draft PR.

Why: This PR is a purely internal navigation refactor. It migrates three RHP routes (NEW_TASK_SHARE_DESTINATION, MONEY_REQUEST_STEP_SEND_FROM, MONEY_REQUEST_STEP_COMPANY_INFO) to dynamic URL navigation — renaming screens to Dynamic*, wiring DYNAMIC_ROUTES + linkingConfig + ModalStackNavigators + types, swapping call sites to createDynamicRoute(...), and using useDynamicBackPath(...) for back navigation. The user-facing flows (Assign task → Share destination, Send invoice → Send from, Send invoice → Company info) are unchanged: same pages, same labels, same buttons, same behavior. Only the internal URL shape of these deep links changes, and legacy URLs are preserved via OldRoutes redirects.

There are no new features, renamed UI labels, tabs, settings, or workflow changes that the help articles document. A search of docs/articles also found no articles that reference these routes or URL paths.

If a follow-up part of this migration introduces a user-visible change (e.g. a new page or a changed label), ping me again and I'll draft the docs update then.

@mitarachim

Copy link
Copy Markdown

@suneox This PR is failing in TC 1 step 4 because of a regression issue #97188

Screenshot 2026-07-28 at 12 36 19 PM

The issue is reproducible in: Web

Bug7219243_1785189850996.tap_share.mp4

@huult

huult commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

@suneox I think we just need to update the precondition to match the correct steps. Could you take a look?

@suneox

suneox commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

I’ll take a look at this one after an hour. It appears that the condition test case 1 has been updated in the latest main.

@suneox

suneox commented Jul 28, 2026

Copy link
Copy Markdown
Contributor Author

@suneox This PR is failing in TC 1 step 4 because of a regression issue #97188

@mitarachim Thanks for flagging this. Based on the current code, TC 1 only reproduces the "Share row is interactive" path when the task draft has no parentReportID, which happens only when isValidReport === false. So we can ignore this test case — I've updated the QA Steps section accordingly

@OSBotify

Copy link
Copy Markdown
Contributor

🚀 Deployed to production by https://github.com/marcaaron in version: 9.4.45-14 🚀

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

Bundle Size Analysis (Sentry):

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.

7 participants