Background
MoneyReportHeader renders on every expense report screen. It handles primary actions (submit, approve, pay), a 20+ option secondary actions dropdown, and 9 modal dialogs - all in a single ~2,040-line file. On every mount, it eagerly constructs config objects for all 20+ secondary actions (translated text, icons, closure handlers) even though only 3-5 are applicable per report state. Profiling shows p50 render at 6.1ms, p95 at 173.5ms, p99 at 255.4ms.
Problem
When MoneyReportHeader mounts, it constructs all 20+ secondary action configs upfront and bundles three unrelated responsibilities into one 2,040-line component, causing unnecessary allocations per mount, frequent merge conflicts across concurrent PRs, and slow code review cycles due to interleaved concerns.
Solution
Decompose into 5 files:
| File |
Responsibility |
MoneyReportHeader.tsx |
Orchestrator - shared subscriptions, layout, status bar |
MoneyReportHeaderContext.tsx |
Ref-stable context for cross-component triggers |
MoneyReportHeaderPrimaryAction.tsx |
Switch-based renderer for the active primary action |
MoneyReportHeaderSecondaryActions.tsx |
Switch-based function building only applicable action configs |
MoneyReportHeaderModals.tsx |
9 modal dialogs, registers triggers on mount |
Key changes:
- Switch over Record - Only configs for applicable actions (3-5 of 20+) get constructed, eliminating ~15 unnecessary object+closure allocations per mount
- Ref-stable context - Modal triggers and payment/approval callbacks shared without re-renders on identity changes
- Mount-once modal registration - Triggers registered once, avoiding stale closure issues
- Single-responsibility files - Changes to modals don't touch action logic; concurrent PRs targeting different concerns no longer conflict
Profiler results:
- p50: 6.1ms to 2.9ms (-52%)
- Total duration: 1345ms to 1297ms (-3.6%)
Related: #77173
Issue Owner
Current Issue Owner: @mallenexpensify
Background
MoneyReportHeaderrenders on every expense report screen. It handles primary actions (submit, approve, pay), a 20+ option secondary actions dropdown, and 9 modal dialogs - all in a single ~2,040-line file. On every mount, it eagerly constructs config objects for all 20+ secondary actions (translated text, icons, closure handlers) even though only 3-5 are applicable per report state. Profiling shows p50 render at 6.1ms, p95 at 173.5ms, p99 at 255.4ms.Problem
When MoneyReportHeader mounts, it constructs all 20+ secondary action configs upfront and bundles three unrelated responsibilities into one 2,040-line component, causing unnecessary allocations per mount, frequent merge conflicts across concurrent PRs, and slow code review cycles due to interleaved concerns.
Solution
Decompose into 5 files:
MoneyReportHeader.tsxMoneyReportHeaderContext.tsxMoneyReportHeaderPrimaryAction.tsxMoneyReportHeaderSecondaryActions.tsxMoneyReportHeaderModals.tsxKey changes:
Profiler results:
Related: #77173
Issue Owner
Current Issue Owner: @mallenexpensify