Shared Logic Refactor
Goal
Reduce duplication, improve consistency, and lower bug risk by extracting reusable logic into shared utils, services, hooks, and shared UI patterns.
How To Use This File
- Mark an item complete only when its Done Criteria are fully met.
- For any task that changes/adds
src/services or src/utils, add/update tests in the same task.
- Keep each item scope-limited; do not bundle multiple large refactors into one PR.
Prioritized Checklist (Most Important -> Least Important)
1. Centralize Financial Calculation Engine
Priority: Critical
Problem: Core pay/tax/net/leftover math is duplicated across multiple layers.
Current duplication evidence:
src/contexts/BudgetContext.tsx (calculatePaycheckBreakdown)
src/components/PayBreakdown/PayBreakdown.tsx (yearly/display breakdown math)
src/components/KeyMetrics/KeyMetrics.tsx (annual/monthly metric math)
src/services/pdfExport.ts (its own gross/tax/net math)
Refactor target:
- Add
src/services/budgetCalculations.ts with pure functions:
calculatePayBreakdownPerPaycheck
calculateAnnualizedSummary
calculateDisplaySummary(displayMode)
calculateAllocationTotals
Done Criteria:
- No component/service performs independent pay/tax/net math outside shared calculator functions.
pdfExport values match PayBreakdown/KeyMetrics outputs for test fixtures.
- New/updated tests exist for
budgetCalculations and all touched services/utils.
Why first: This removes the highest bug surface area and guarantees all screens/export use identical numbers.
2. Unified Missing/Moved File Relink Flow
Priority: Critical
Problem: Similar relink state + modal handling exists in multiple components.
Current duplication evidence:
src/components/WelcomeScreen/WelcomeScreen.tsx
src/components/PlanDashboard/PlanDashboard.tsx
- Shared behavior depends on
FileStorageService.relinkMovedBudgetFile
Refactor target:
- Add
src/hooks/useFileRelinkFlow.ts (or a small service + hook pair)
- Keep modal visuals local if desired, but centralize decision/state logic:
- open/cancel/retry
- invalid/mismatch message handling
- stale path cleanup policy
Why second: Prevents regressions in file safety logic and keeps save/load behavior consistent.
Done Criteria:
- Welcome and PlanDashboard use a common relink flow contract.
- Saving cannot proceed to stale paths from any trigger (
button, menu, keyboard shortcut).
- Shared tests cover all status outcomes.
3. File Path / Plan Name Helpers
Priority: High
Problem: Path-to-name parsing logic is duplicated in context/service and ad-hoc splits exist.
Current duplication evidence:
src/contexts/BudgetContext.tsx (derivePlanNameFromFilePath)
src/services/fileStorage.ts (derivePlanNameFromFilePath and repeated basename extraction)
Refactor target:
- Add
src/utils/filePath.ts:
getBaseFileName(path)
getPlanNameFromPath(path)
stripFileExtension(name)
Why third: Low risk and immediately improves consistency.
Done Criteria:
- Only shared helpers are used for plan-name derivation and basename extraction.
- No direct
split(/[\\/]) basename parsing remains in business logic.
4. Shared Dialog Strategy (Replace scattered alert / confirm)
Priority: High
Problem: Browser dialogs are still scattered and inconsistent for UX/testing.
Current duplication evidence:
PlanDashboard, Settings, WelcomeScreen, SetupWizard, EncryptionSetup, PlanTabs, and manager components.
Refactor target:
- Add shared modal-based helpers:
ConfirmDialog
ErrorDialog
- optional
useAppDialogs
Why fourth: Better UX consistency and testability.
Done Criteria:
- Critical flows no longer rely on native
window.alert/window.confirm.
- Dialog interaction behavior is consistent and keyboard-accessible.
5. Manager CRUD Form Patterns -> Shared Hooks
Priority: High
Problem: Bills/Loans/Savings/Benefits managers all implement similar modal-form CRUD state and validation patterns.
Current duplication evidence:
- Add/edit modal toggles and
editingX patterns
handleAdd*, handleEdit*, handleSave*, handleDelete* duplication
Refactor target:
- Add hooks:
useModalEntityEditor<T>()
useFieldErrors<T>()
useDeleteConfirmation()
Why fifth: Large maintainability win, but higher refactor complexity than utility-only changes.
Done Criteria:
- Repeated
handleAdd/Edit/Save/Delete scaffolding is reduced substantially across managers.
- No behavior regressions in add/edit/delete flows.
6. Display Mode Conversion Utilities
Priority: Medium-High
Problem: Local toDisplayAmount helpers repeated across managers.
Current duplication evidence:
BillsManager, SavingsManager, PayBreakdown, and related components.
Refactor target:
- Add
src/utils/displayAmounts.ts:
toDisplayAmount(perPaycheck, paychecksPerYear, mode)
fromDisplayAmount(value, paychecksPerYear, mode)
Why now: Reduces small arithmetic drift and simplifies components.
Done Criteria:
- All display amount conversions route through one shared utility API.
7. Suggested Leftover Logic
Priority: Medium
Problem: Same suggestion formula exists in setup and pay settings modal.
Current duplication evidence:
SetupWizard
PaySettingsModal
Refactor target:
- Add
src/utils/paySuggestions.ts:
Done Criteria:
- Setup and modal produce identical suggestion values for the same inputs.
getSuggestedLeftoverPerPaycheck(grossPerPaycheck)
formatSuggestedLeftover(...) if needed
8. Split And Rename auth.ts Types
Priority: Medium
Problem: src/types/auth.ts has become a catch-all type file for the entire app, and the name no longer matches the domain.
Current duplication / maintenance evidence:
- Unrelated budget, account, tax, loan, tab, and settings types all live in one file.
- New shared services and components continue importing from
auth.ts, increasing coupling and search noise.
- The filename suggests authentication concerns even though this app does not have an auth domain.
Refactor target:
- Split
src/types/auth.ts into clearer modules such as:
src/types/budget.ts
src/types/accounts.ts
src/types/payroll.ts
src/types/settings.ts
src/types/tabs.ts
- Optionally keep a temporary barrel during migration if needed, but the end state should avoid
auth.ts as the main import surface.
Why here: This is foundational cleanup for Phase 2 and later shared-service work, because type sprawl will otherwise keep leaking into every new abstraction.
Done Criteria:
- New code no longer imports app domain types from
src/types/auth.ts.
- Domain types are grouped into smaller files with clearer names.
- Any compatibility barrel is temporary and no longer the default import target.
9. Budget Currency Conversion as Service
Priority: Medium
Problem: Deep budget amount conversion currently lives in component-level modal logic.
Current duplication evidence:
PaySettingsModal (convertBudgetAmounts)
Refactor target:
- Add
src/services/budgetCurrencyConversion.ts:
Done Criteria:
- Component only orchestrates UI; conversion logic lives in service with tests.
convertBudgetAmounts(data, rate)
roundCurrency helper
10. Account Grouping and Totals Helpers
Priority: Medium
Problem: Multiple account-grouping reducers and subtotal patterns exist in managers.
Current duplication evidence:
BillsManager, LoansManager, SavingsManager
Refactor target:
- Add
src/utils/accountGrouping.ts:
Done Criteria:
- Manager components use shared grouping functions for account-based list construction.
groupByAccountId
buildAccountRows
sumByFrequency
11. Shared ViewMode Type
Priority: Medium-Low
Problem: 'paycheck' | 'monthly' | 'yearly' is redeclared in many places.
Refactor target:
- Add
src/types/viewMode.ts and import everywhere.
Done Criteria:
- No local re-declarations of
ViewMode union remain in components.
12. Encryption Setup Flow Consolidation
Priority: Medium-Low
Problem: Encryption setup/save behavior is distributed across SetupWizard, EncryptionSetup, and PlanDashboard handlers.
Refactor target:
- Add
src/services/encryptionSetupService.ts or useEncryptionSetupFlow(planId).
Done Criteria:
- One flow controls key generation, validation, save, and error messaging.
13. Shared Path Display Styling Utility
Priority: Low
Problem: Similar relink modal path styling classes exist in multiple component CSS files.
Refactor target:
- Add one shared utility class for code/path blocks in a shared stylesheet.
Done Criteria:
- Path display styling is defined once and reused.
14. Remove/Archive Backup and Unused Artifacts
Priority: Low (Hygiene)
Problem: *.backup files and likely unused component artifacts increase confusion.
Current candidates:
src/components/BenefitsManager/*.backup
src/components/LoansManager/*.backup
src/components/_shared/Button/*.backup
Refactor target:
- Remove from active tree (or move to an archive folder outside
src).
Done Criteria:
- Active source tree has no backup artifacts that can be confused with runtime code.
Phased Execution Plan
Phase 1 (Low Risk, High ROI)
Phase 2 (Core correctness)
Phase 3 (Workflow consistency)
Phase 4 (Form architecture)
Phase 5 (Cleanup)
Test Strategy Requirements
Success Metrics
Shared Logic Refactor
Goal
Reduce duplication, improve consistency, and lower bug risk by extracting reusable logic into shared
utils,services, hooks, and shared UI patterns.How To Use This File
src/servicesorsrc/utils, add/update tests in the same task.Prioritized Checklist (Most Important -> Least Important)
1. Centralize Financial Calculation Engine
Priority: Critical
src/services/budgetCalculations.tsas the single source of truth for paycheck/tax/net/allocation math.BudgetContext.calculatePaycheckBreakdownto use shared functions.KeyMetricsandpdfExportto use the same shared functions.PayBreakdownto use the same shared functions.Problem: Core pay/tax/net/leftover math is duplicated across multiple layers.
Current duplication evidence:
src/contexts/BudgetContext.tsx(calculatePaycheckBreakdown)src/components/PayBreakdown/PayBreakdown.tsx(yearly/display breakdown math)src/components/KeyMetrics/KeyMetrics.tsx(annual/monthly metric math)src/services/pdfExport.ts(its own gross/tax/net math)Refactor target:
src/services/budgetCalculations.tswith pure functions:calculatePayBreakdownPerPaycheckcalculateAnnualizedSummarycalculateDisplaySummary(displayMode)calculateAllocationTotalsDone Criteria:
pdfExportvalues matchPayBreakdown/KeyMetricsoutputs for test fixtures.budgetCalculationsand all touched services/utils.Why first: This removes the highest bug surface area and guarantees all screens/export use identical numbers.
2. Unified Missing/Moved File Relink Flow
Priority: Critical
src/hooks/useFileRelinkFlow.ts(or equivalent service + hook).success,cancelled,mismatch, andinvalidpaths.Problem: Similar relink state + modal handling exists in multiple components.
Current duplication evidence:
src/components/WelcomeScreen/WelcomeScreen.tsxsrc/components/PlanDashboard/PlanDashboard.tsxFileStorageService.relinkMovedBudgetFileRefactor target:
src/hooks/useFileRelinkFlow.ts(or a small service + hook pair)Why second: Prevents regressions in file safety logic and keeps save/load behavior consistent.
Done Criteria:
button, menu, keyboard shortcut).3. File Path / Plan Name Helpers
Priority: High
src/utils/filePath.tsfor all filename/path parsing.BudgetContextandFileStorageService.Problem: Path-to-name parsing logic is duplicated in context/service and ad-hoc splits exist.
Current duplication evidence:
src/contexts/BudgetContext.tsx(derivePlanNameFromFilePath)src/services/fileStorage.ts(derivePlanNameFromFilePathand repeated basename extraction)Refactor target:
src/utils/filePath.ts:getBaseFileName(path)getPlanNameFromPath(path)stripFileExtension(name)Why third: Low risk and immediately improves consistency.
Done Criteria:
split(/[\\/])basename parsing remains in business logic.4. Shared Dialog Strategy (Replace scattered
alert/confirm)Priority: High
ConfirmDialog,ErrorDialog) and optionaluseAppDialogshelper.alert/confirmcalls first (PlanDashboard, Settings, SetupWizard, Welcome).Cancel,Confirm,Retry) and error presentation.Problem: Browser dialogs are still scattered and inconsistent for UX/testing.
Current duplication evidence:
PlanDashboard,Settings,WelcomeScreen,SetupWizard,EncryptionSetup,PlanTabs, and manager components.Refactor target:
ConfirmDialogErrorDialoguseAppDialogsWhy fourth: Better UX consistency and testability.
Done Criteria:
window.alert/window.confirm.5. Manager CRUD Form Patterns -> Shared Hooks
Priority: High
Problem: Bills/Loans/Savings/Benefits managers all implement similar modal-form CRUD state and validation patterns.
Current duplication evidence:
editingXpatternshandleAdd*,handleEdit*,handleSave*,handleDelete*duplicationRefactor target:
useModalEntityEditor<T>()useFieldErrors<T>()useDeleteConfirmation()Why fifth: Large maintainability win, but higher refactor complexity than utility-only changes.
Done Criteria:
handleAdd/Edit/Save/Deletescaffolding is reduced substantially across managers.6. Display Mode Conversion Utilities
Priority: Medium-High
src/utils/displayAmounts.tsand migrate manager-leveltoDisplayAmount/fromDisplayAmounthelpers.Problem: Local
toDisplayAmounthelpers repeated across managers.Current duplication evidence:
BillsManager,SavingsManager,PayBreakdown, and related components.Refactor target:
src/utils/displayAmounts.ts:toDisplayAmount(perPaycheck, paychecksPerYear, mode)fromDisplayAmount(value, paychecksPerYear, mode)Why now: Reduces small arithmetic drift and simplifies components.
Done Criteria:
7. Suggested Leftover Logic
Priority: Medium
src/utils/paySuggestions.ts.Problem: Same suggestion formula exists in setup and pay settings modal.
Current duplication evidence:
SetupWizardPaySettingsModalRefactor target:
src/utils/paySuggestions.ts:Done Criteria:
getSuggestedLeftoverPerPaycheck(grossPerPaycheck)formatSuggestedLeftover(...)if needed8. Split And Rename
auth.tsTypesPriority: Medium
src/types/auth.tsinto smaller domain-focused type files.auth.tsentry point with a narrow compatibility barrel during migration.Problem:
src/types/auth.tshas become a catch-all type file for the entire app, and the name no longer matches the domain.Current duplication / maintenance evidence:
auth.ts, increasing coupling and search noise.Refactor target:
src/types/auth.tsinto clearer modules such as:src/types/budget.tssrc/types/accounts.tssrc/types/payroll.tssrc/types/settings.tssrc/types/tabs.tsauth.tsas the main import surface.Why here: This is foundational cleanup for Phase 2 and later shared-service work, because type sprawl will otherwise keep leaking into every new abstraction.
Done Criteria:
src/types/auth.ts.9. Budget Currency Conversion as Service
Priority: Medium
convertBudgetAmounts+ rounding logic fromPaySettingsModaltosrc/services/budgetCurrencyConversion.ts.Problem: Deep budget amount conversion currently lives in component-level modal logic.
Current duplication evidence:
PaySettingsModal(convertBudgetAmounts)Refactor target:
src/services/budgetCurrencyConversion.ts:Done Criteria:
convertBudgetAmounts(data, rate)roundCurrencyhelper10. Account Grouping and Totals Helpers
Priority: Medium
src/utils/accountGrouping.tshelpers for repeated reducers/grouping.Problem: Multiple account-grouping reducers and subtotal patterns exist in managers.
Current duplication evidence:
BillsManager,LoansManager,SavingsManagerRefactor target:
src/utils/accountGrouping.ts:Done Criteria:
groupByAccountIdbuildAccountRowssumByFrequency11. Shared
ViewModeTypePriority: Medium-Low
src/types/viewMode.ts.'paycheck' | 'monthly' | 'yearly'declarations with imported type.Problem:
'paycheck' | 'monthly' | 'yearly'is redeclared in many places.Refactor target:
src/types/viewMode.tsand import everywhere.Done Criteria:
ViewModeunion remain in components.12. Encryption Setup Flow Consolidation
Priority: Medium-Low
Problem: Encryption setup/save behavior is distributed across SetupWizard, EncryptionSetup, and PlanDashboard handlers.
Refactor target:
src/services/encryptionSetupService.tsoruseEncryptionSetupFlow(planId).Done Criteria:
13. Shared Path Display Styling Utility
Priority: Low
Problem: Similar relink modal path styling classes exist in multiple component CSS files.
Refactor target:
Done Criteria:
14. Remove/Archive Backup and Unused Artifacts
Priority: Low (Hygiene)
*.backupfiles outsidesrc.BenefitsManageris intentionally unused; either wire it or remove it.Problem:
*.backupfiles and likely unused component artifacts increase confusion.Current candidates:
src/components/BenefitsManager/*.backupsrc/components/LoansManager/*.backupsrc/components/_shared/Button/*.backupRefactor target:
src).Done Criteria:
Phased Execution Plan
Phase 1 (Low Risk, High ROI)
filePath.ts)ViewModetypePhase 2 (Core correctness)
budgetCalculationsservicePayBreakdown,KeyMetrics,pdfExport, and context calculations to shared enginesrc/types/auth.tsinto domain type modulesPhase 3 (Workflow consistency)
ConfirmDialog/ErrorDialog)alert/confirmusagePhase 4 (Form architecture)
Phase 5 (Cleanup)
componentsdirectory to group related components together: tab-driven plan views undertabViews, separate non-plan windows underviews, and_sharedcomponents into more intuitive subgroups.src/constantsdirectory, split out by files that make sense, and update importsTest Strategy Requirements
src/servicesorsrc/utilsmodule includes updated tests.src/services/*.tsorsrc/utils/*.tsmodule includes a matching*.test.ts.Success Metrics
alert/confirmcalls in app components.