ReportActionCompose 5/6: extract attachment hooks#88391
ReportActionCompose 5/6: extract attachment hooks#88391cristipaval merged 9 commits intoExpensify:mainfrom
Conversation
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ Changes either increased or maintained existing code coverage, great job!
|
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@codex review |
|
Codex Review: Didn't find any major issues. Chef's kiss. ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
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". |
|
@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] |
|
PR doesn’t need product input as a refactor PR. Unassigning and unsubscribing myself. |
| {ReceiptPDFValidation} | ||
| {ReceiptErrorModal} |
There was a problem hiding this comment.
This looks unnecesary,
There was a problem hiding this comment.
valid, removing
Reviewer Checklist
Screenshots/VideosAndroid: HybridAppAndroid: mWeb ChromeScreen.Recording.2026-04-23.at.16.38.33.moviOS: HybridAppScreen.Recording.2026-04-24.at.21.22.41.moviOS: mWeb SafariScreen.Recording.2026-04-23.at.16.37.34.movMacOS: Chrome / SafariScreen.Recording.2026-04-23.at.16.31.11.movScreen.Recording.2026-04-23.at.16.32.53.mov |
|
@adhorodyski One comment, the rest looks great. |
|
@adhorodyski I got a crash on both IOS and Android (doesn't happen on main) Screen.Recording.2026-04-23.at.16.51.16.mov |
Screen.Recording.2026-04-24.at.13.33.42.mp4I was able to reproduce it, the latest commit fixes it :) |
…attachment-hooks # Conflicts: # src/pages/inbox/report/ReportActionCompose/ReportActionCompose.tsx
|
🚧 @cristipaval 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! 🧪🧪
|
|
✋ This PR was not deployed to staging yet because QA is ongoing. It will be automatically deployed to staging after the next production release. |
|
🚀 Deployed to staging by https://github.com/cristipaval in version: 9.3.62-5 🚀
Bundle Size Analysis (Sentry): |
|
No help site changes required. This PR is a purely internal refactoring of |
|
🚀 Deployed to staging by https://github.com/cristipaval in version: 9.3.64-0 🚀
Bundle Size Analysis (Sentry): |
Explanation of Change
PR 5/6 in the ReportActionCompose decomposition series (issue #87097).
Extracts the entire attachment + DropZone subsystem from the orchestrator into 3 self-contained hooks and 1 compound component. Replaces the monolithic 220-LOC
useAttachmentUploadValidationwith:useShouldAddOrReplaceReceipt(42 LOC) — pure derivation; resolves{shouldAddOrReplaceReceipt, transactionID}for receipt edit gating.useAttachmentPicker(100 LOC) — file pick / clean / validate / preview modal lifecycle. CallsclearComposer()fromComposerActionscontext after the user confirms.useReceiptDrop(120 LOC) — receipt drop →replaceReceiptorinitMoneyRequest+ draft transactions + navigation. Owns ~10 Onyx subscriptions that only fire for receipt drops.ComposerDropZone(164 LOC) — two-level drop UI. Rooms/groups/invoices hitSimpleDropZone(cheap, no extra subs); everything else hitsRichDropZonewhich derivesshouldDisplayDualDropZoneand mountsDualDropZonevsDragAndDropConsumer+DropZoneUI.Each of the three callsites (
ComposerActionMenu,ComposerInput,ComposerDropZone) now callsuseAttachmentPicker(reportID)directly — no moreonAttachmentPicked/onPasteFileprop threading. Each callsite gets its ownuseFilesValidationinstance; only the active flow fires validation UI, inactive instances rendernull.Orchestrator: 220 → 69 LOC. The attachment derivation block, all related Onyx subscriptions, the DropZone render, and the validation plumbing are gone.
ReportActionCompose.tsxis now pure composition:<ComposerLocalTime>,<ComposerDropZone>wrapping<ComposerBox>with its 4 children (ActionMenu,Input,EmojiPicker,SendButton), and<ComposerFooter>.Deleted:
useAttachmentUploadValidation.ts(-220 LOC) — fully replaced.After this PR, only PR 6 remains (Suggestions self-subscribe + manual memo cleanup — independent of this PR).
💡 Review with Hide whitespace.
Fixed Issues
$ #87097
PROPOSAL:
Tests
Critical — attachment picker
+menu → pick image → caption → send → message posts with attachment + caption. Composer clears.+menu → pick PDF → PDF validation preview appears → confirm → attachment modal shows → send.+menu → pick invalid file (e.g. too large) → ErrorModal appears with correct copy.+menu → pick file → preview modal opens; message text preserved until send.Critical — drop zone
Regression — behavior preservation
Smoke
+menu placement unchanged).Offline tests
+menu pick file → send → message queues with attachment, reconnect → syncs.QA Steps
Same as tests
PR Author Checklist
### Fixed Issuessection aboveTestssectionOffline stepssectionQA stepssectiontoggleReportand notonIconClick)src/languages/*files and using the translation methodSTYLE.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.Screenshots/Videos
Android: Native
Android: mWeb Chrome
iOS: Native
iOS: mWeb Safari
MacOS: Chrome / Safari