feat(THI-51): modernize revenue & expenses tab - #21
Merged
tdody merged 2 commits intoApr 19, 2026
Merged
Conversation
Rebuild the Revenue & Expenses tab around the THI-45/46 design system with a 2-column (1fr + 340px) sticky layout. New primitive - shared/SeasonalBars.tsx: 12-bar SVG chart with peak-month color differentiation; exports derivePeakMask helper that centers N peak months around July. Used in the seasonal occupancy panel. Main-column structure (STR) - Segmented rental-type switcher at top (STR / LTR) - FormSection: Revenue — nightly rate, cleaning fee, stay length, rental delay, platform fee %, property mgmt % - Occupancy panel (custom FormSection) — Toggle for seasonal mode, sliders for Peak Months / Peak Occupancy / Off-Peak Occupancy / Weighted Effective (read-only), SeasonalBars chart with peak/off-peak coloring. Advanced <details> exposes the existing MonthlyProfileEditor for per-month overrides. - FormSection: Operating Expenses (8 fields) — cleaning cost/turn, utilities, supplies, marketing, software, lawn & snow, other monthly, insurance - FormSection: Reserves (3 SliderFields) — maintenance / capex / damage - FormSection: Professional Fees — accounting, legal - <details> Vermont tax configuration (collapsible) — 5 %-fields + registration fee + Platform Remits Tax Toggle - <details> Growth & Exit (shared fields, collapsible) LTR structure mirrors STR with lease-focused revenue fields, 8 operating expenses, 2-slider reserves, and the shared Growth & Exit block. Sticky preview aside - Border-rule card showing Monthly Revenue, Monthly Expenses, Monthly Cashflow fetched from getResults / getLTRResults. Refreshes on mount and after every save. Positive cashflow in accent; negative in negative tone. Preserved behavior - STR ↔ LTR switch (Segmented now replaces the sky/violet pill buttons) - Shared-field sync between STR/LTR forms via updateSharedField - Dual-persistence save logic (active type first, then sync shared to the other type) - MonthlyProfileEditor still available (now under Advanced details disclosure) - All tooltip-driven helper text kept (the fields still accept tooltips via their existing props, though the rewrite defers surfacing most copy to keep the layout tight — can re-add with the hint prop in follow-up) Wiring - PropertyDetail.tsx now passes `propertyId` into RevenueExpensesTab so the preview can call getResults / getLTRResults. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SeasonalBars.tsx was exporting both a component and the derivePeakMask helper, which breaks Vite fast refresh. Inline the helper into RevenueExpensesTab (its only consumer) and keep SeasonalBars as a pure component export. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Rebuilds the Revenue & Expenses tab around the THI-45/46 design system with a 2-column (1fr + 340px) sticky layout, plus a new
<SeasonalBars>primitive.New primitive
shared/SeasonalBars.tsx— 12-bar SVG chart with peak-month color differentiation (accent for peak, ink-3/50% for off-peak). ExportsderivePeakMask(peakMonths)that centers N peak months around July.Main column (STR)
<SeasonalBars>showing the implied 12-month profile. Advanced<details>exposes the existingMonthlyProfileEditorfor per-month overrides.<details>Vermont tax configuration (collapsible) — 5 % fields + registration fee + Platform Remits Tax<Toggle><details>Growth & Exit (collapsible, shared fields)LTR
Mirrors the STR structure with lease-focused revenue (monthly rent, lease duration, pet rent, late fee, vacancy rate, lease-up), 8 operating expenses, 2-slider reserves, and the shared Growth & Exit block.
Sticky preview aside
Border-rule card showing Monthly Revenue, Monthly Expenses, Monthly Cashflow fetched from
getResults/getLTRResults. Refreshes on mount and after every save. Positive cashflow in accent tone; negative in negative tone.Preserved behavior
MonthlyProfileEditor(now under Advanced disclosure; token-ified colors)RevenueExpensesTabonly gains a newpropertyIdprop, threaded through inPropertyDetail.tsxScope notes
tooltipprop via CurrencyInput / PercentInput where useful (tooltip copy preserved in the file — can re-surface viahintprop in a polish follow-up).Test plan
npm run build— passes, CSS 54.19 kB, JS 464.21 kB (-8 kB from dead-code elimination), 117 modules🤖 Generated with Claude Code