Skip to content

Decompose ReportActionCompose into compound Composer component#46

Draft
adhorodyski wants to merge 65 commits intomainfrom
decompose/report-action-composer-v2
Draft

Decompose ReportActionCompose into compound Composer component#46
adhorodyski wants to merge 65 commits intomainfrom
decompose/report-action-composer-v2

Conversation

@adhorodyski
Copy link
Copy Markdown
Collaborator

Summary

Decomposes the 730-LOC ReportActionCompose monolith (with ~24 Onyx subscriptions) into a compound Composer component architecture where each child self-subscribes to only the data it needs.

Key changes:

  • 4 contexts split by change frequency: ComposerMeta (refs, stable), ComposerState (isFocused, isFullComposerAvailable), ComposerSendState (isEmpty, exceededMaxLength, isSendDisabled), ComposerActions (stable functions) — prevents unnecessary re-renders from context changes
  • Compound component API: Composer.DropZone, Composer.LocalTime, Composer.ActionMenu, Composer.Input, Composer.EmojiPicker, Composer.SendButton, Composer.Footer — each self-subscribing, guard-wrapped where appropriate
  • Extracted hooks: useComposerSubmit, useComposerFocus, useAttachmentPicker, useReceiptDrop, useLastEditableAction — co-located logic that was previously interleaved in the monolith
  • SuggestionMention fix: Removed double subscription, self-subscribes to its own data, removed manual memoization (React Compiler handles it)
  • Deleted: useAttachmentUploadValidation (replaced by useAttachmentPicker + useReceiptDrop), ComposerBoxContext (merged into ComposerMeta), dead code and manual React.memo wrappers
  • Orchestrator reduced to ~60 LOC: Only composes children and provides the ComposerProvider
  • Wraps PopoverMenu and EmojiPicker in <Activity> to skip hidden subtree reconciliation

Test plan

  • Open any chat report — composer renders, can type and send messages
  • Attach a file via the action menu (+) button — preview shows, can send
  • Drag-and-drop a file onto the composer — drop zone appears, file attaches
  • Verify emoji picker opens/closes, inserts emoji into composer
  • Verify participant local time shows for DMs across timezones
  • Press arrow-up on empty composer to edit the last sent message
  • Verify composer focus/blur works correctly when switching reports
  • Test on mobile web — composer should behave identically
  • Verify the composer footer (offline indicator, blocked from Concierge message) displays correctly
  • Open a report that has Concierge blocked — verify send is disabled
  • Type a very long message (>10k chars) — verify exceededMaxLength warning appears
  • Verify no regressions in suggestion popover (mentions, emoji autocomplete)

🤖 Generated with Claude Code

ShridharGoel and others added 30 commits March 10, 2026 23:56
…tate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ents

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tion

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
adhorodyski and others added 27 commits April 2, 2026 17:36
…ubmit from provider

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ze-systemmessage

# Conflicts:
#	src/pages/inbox/report/PureReportActionItem.tsx
… header

PayPrimaryAction was missing the hasOnlyNonReimbursableTransactions check
that PayActionButton (preview) already had, causing onlyShowPayElsewhere
to be true for non-reimbursable reports. This made SettlementButton show
only "Mark as Paid" instead of also showing "Pay with Business Account".

Co-authored-by: {"message":"Not Found","documentation_url":"https://docs.github.com/rest/issues/comments#get-an-issue-comment","status":"404"} <{"message":"Not Found","documentation_url":"https://docs.github.com/rest/issues/comments#get-an-issue-comment","status":"404"}@users.noreply.github.com>
…/84192-bump-onyx-3.0.57

Bump react-native-onyx from 3.0.54 to 3.0.57.
…mmessage

Implement system message for card freeze and unfreeze actions
Co-authored-by: situchan <108292595+situchan@users.noreply.github.com>
Co-authored-by: Situ Chandra Shil <situchan@users.noreply.github.com>
fix: Per attendee amount on the table does not show negative sign
…rsablePayHeaderButtons

[CP Staging] Fix non-reimbursable pay button options in report header
Refactor `deleteMoneyRequest` to pass data
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 3, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 99571d38-1e1c-4030-9d7a-0d8fe1b09824

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch decompose/report-action-composer-v2

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

selectedTransactionIDs,
allTransactionViolationsParam,
currentUserAccountID,
currentUserEmail,
title,
description: '',
assigneeEmail: assignee?.login ?? '',
currentUserAccountID: currentUserPersonalDetails.accountID,
notifyReportID: reportID,
ancestors: targetReportAncestors,
attachments: attachmentFileRef.current,
currentUserAccountID: currentUserPersonalDetails.accountID,
ancestors: targetReportAncestors,
text: newCommentTrimmed,
timezoneParam: currentUserPersonalDetails.timezone ?? CONST.DEFAULT_TIME_ZONE,
currentUserAccountID: currentUserPersonalDetails.accountID,
const [newParentReport] = useOnyx(`${ONYXKEYS.COLLECTION.REPORT}${report?.parentReportID}`);
const [currentDate] = useOnyx(ONYXKEYS.CURRENT_DATE);
const [policyCategories] = useOnyx(`${ONYXKEYS.COLLECTION.POLICY_CATEGORIES}${policy?.id}`);
const [ownerBillingGracePeriodEnd] = useOnyx(ONYXKEYS.NVP_PRIVATE_OWNER_BILLING_GRACE_PERIOD_END);
const [amountOwed] = useOnyx(ONYXKEYS.NVP_PRIVATE_AMOUNT_OWED);
const personalPolicy = usePersonalPolicy();
const [allPolicies] = useOnyx(ONYXKEYS.COLLECTION.POLICY);
const [userBillingGracePeriodEnds] = useOnyx(ONYXKEYS.COLLECTION.SHARED_NVP_PRIVATE_USER_BILLING_GRACE_PERIOD_END);
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.