Refactor utilities, types, and components for improved organization#37
Merged
kryptodrex merged 34 commits intodevelopfrom Mar 14, 2026
Merged
Refactor utilities, types, and components for improved organization#37kryptodrex merged 34 commits intodevelopfrom
kryptodrex merged 34 commits intodevelopfrom
Conversation
Introduce three new utility modules with tests: displayAmounts (wrappers around payPeriod conversions plus monthlyToDisplayAmount), filePath (getBaseFileName, stripFileExtension, getPlanNameFromPath with robust path/extension handling), and paySuggestions (leftover suggestion algorithm with rounding/minimum and currency formatting). Also update payPeriod to import and use the ViewMode type in its conversion and label functions. Tests cover conversion accuracy, edge cases, path normalization, and formatting behavior.
Extract large monolithic src/types/auth.ts into dedicated type modules for better organization and maintainability. Added new files: src/types/accounts.ts, budget.ts, budgetContext.ts, frequencies.ts, obligations.ts, payroll.ts, settings.ts, tabs.ts, viewMode.ts and updated src/types/auth.ts to re-export the new modules. Introduces interfaces and type aliases for accounts, budget data, budget context, frequencies, obligations (bills/loans/savings), payroll (pay settings, deductions, taxes, benefits, retirement), settings, tabs, and view modes to simplify imports and reduce file size of the original auth types.
Introduce budgetCalculations.ts with paycheck/annual/display breakdown helpers (calculatePaycheckBreakdown, calculateAnnualizedPayBreakdown, calculateDisplayPayBreakdown, calculateAnnualizedPaySummary) and accompanying tests. Update pdfExport to consume the shared paycheck breakdown (replacing ad-hoc math) and extend pdfExport.test to assert metrics use the new totals. Also refactor FileStorageService to use getBaseFileName/getPlanNameFromPath utilities when deriving file/plan names.
Replace local derivePlanNameFromFilePath and in-file paycheck calculation with shared utility functions. Import getPlanNameFromPath to derive plan names from file paths and delegate paycheck breakdown to budgetCalculations (calculatePaycheckBreakdown and getEmptyPaycheckBreakdown). This centralizes parsing and payroll logic, reduces duplication, and keeps BudgetContext focused on state management.
Centralize display-mode conversion logic and adopt the shared ViewMode type across multiple components. Replaced local convertToDisplayMode/convertFromDisplayMode helpers with utils/displayAmounts (toDisplayAmount, fromDisplayAmount, monthlyToDisplayAmount), removed duplicate conversion implementations, and updated component props to use ViewMode. Also integrated calculation helpers from services (calculateAnnualizedPaySummary, calculateAnnualizedPayBreakdown) and paySuggestions utilities (getSuggestedLeftoverPerPaycheck, formatSuggestedLeftover) to unify pay/tax/suggestion logic. Updated ViewModeSelector typing and adjusted formatting calls accordingly. Affected files include BenefitsManager, BillsManager, KeyMetrics, LoansManager, PayBreakdown, PaySettingsModal, PlanDashboard, SavingsManager, SetupWizard, TaxBreakdown, and the shared ViewModeSelector.
Move and reorganize TypeScript type imports previously from types/auth into domain-specific modules (types/accounts, types/payroll, types/obligations, types/frequencies, types/tabs, types/budget, types/budgetContext, types/settings). Update import paths across components, contexts, services, and utils to reference the new type files. No runtime logic changes — this is a types-only refactor to improve type organization and clarity.
Fix accounts handling when localStorage contains invalid JSON: on parse failure, create default accounts, persist them via saveAccounts, and return them (removed error logging). Also correct the Account type import path (from ../types/auth to ../types/accounts). Update tests to assert fallback length and that localStorage now contains valid JSON after recovery.
Introduce useFileRelinkFlow hook and tests, wire it into hooks index, and extend FileStorageService for relinking scenarios. The hook manages missing-file prompt state, relink mismatch messages, loading state, and calls FileStorageService.relinkMovedBudgetFile; it invokes an onRelinkSuccess callback on success. Added unit tests for the hook (prompting, mismatch, success) and expanded fileStorage tests to cover relink picker cancelled, mismatch, and successful relink that updates recent-file metadata. Also made addRecentFileForPlan non-private (static) to support recent-file updates during relink handling.
Introduce a shared FileRelinkModal component and styles, and replace duplicated relink modals in PlanDashboard and WelcomeScreen with the new component. Both components were refactored to use the useFileRelinkFlow hook (centralizing relink state/logic), removing duplicated state and handlers and wiring up success/clear callbacks. Minor related updates: export FileRelinkModal from shared index, move relink CSS into the new file and remove the copies, adjust tab rendering/deps (temporarilyVisibleTab handling and tabConfigs dependency), and update save/button disabled checks to use the new missingFile state.
Replace the previous alert+null-return when decryption max attempts are reached with throwing an Error so callers can handle failures programmatically. Adds a unit test that simulates repeated wrong keys for an encrypted plan file and asserts loadBudget rejects with the new error message.
Introduce useAppDialogs to manage confirm and error dialog state (with default labels and callback handling). Add comprehensive tests (mocking React hooks) that verify opening/closing dialogs and invoking confirm/cancel/close callbacks. Export the new hook from hooks index. Also rename a helper in useFileRelinkFlow.test.ts from renderHook to useTestHook for consistency.
Replace native alert() calls with the centralized ErrorDialog managed by useAppDialogs in src/contexts/BudgetContext.tsx. Imports useAppDialogs and ErrorDialog, call openErrorDialog with title/message/actionLabel on save/load/select-save-location errors, add openErrorDialog to relevant dependency arrays, and render the ErrorDialog inside the provider using errorDialog/closeErrorDialog. Console.error remains for logging; UX now uses the app dialog instead of browser alerts.
Add reusable ConfirmDialog and ErrorDialog components (with CSS and index exports) and wire them into the app via the useAppDialogs hook. Replace window.confirm/alert usage with openConfirmDialog/openErrorDialog calls across multiple components (BenefitsManager, BillsManager, LoansManager, SavingsManager, PlanTabs, PlanDashboard, PaySettingsModal, EncryptionSetup, SetupWizard, Settings, WelcomeScreen) to provide consistent, styled modal confirmations and error reporting. Also export the new dialog components from the shared index. This centralizes dialog behavior and improves UX by replacing native alerts/confirms with app modals.
Add two new reusable hooks: useModalEntityEditor (manages modal open/edit state and selected entity) and useFieldErrors (stores and clears per-field validation errors). Add unit tests for both hooks that mock React state/callback behavior. Export the new hooks from src/hooks/index.ts so they're available to consumers.
Replace local modal and error state with shared hooks in BillsManager and LoansManager. Introduces useModalEntityEditor to manage open/edit state for entities and useFieldErrors to centralize validation errors; wires modal isOpen/onClose to the editor, clears errors on open/close, and uses clearFieldError on input changes. Minor form/handler adjustments to call editor.openForCreate/openForEdit and editor.closeEditor. No functional changes intended—refactor reduces duplication and standardizes modal/error handling.
Introduce account grouping utilities and tests. Adds generic helpers: groupByAccountId (groups items by accountId), buildAccountRows (constructs AccountRow entries, excludes empty accounts and sorts by totalMonthly desc), and getAccountNameById (returns account name or 'Unknown Account' fallback). Includes Vitest tests covering grouping, row building/sorting, exclusion of empty accounts, and fallback name behavior.
Replace inline account grouping and row-building logic with shared utilities (groupByAccountId, buildAccountRows, getAccountNameById) to centralize and deduplicate code. Updated BillsManager, LoansManager and SavingsManager to import and use these helpers, simplified mapping and sorting of account rows, and removed a local getAccountName implementation in SavingsManager. No functional behavior changes intended—just refactoring for clarity and reuse.
Move currency conversion and rounding logic out of PaySettingsModal into a new reusable service (src/services/budgetCurrencyConversion.ts) and add unit tests (src/services/budgetCurrencyConversion.test.ts). PaySettingsModal now imports convertBudgetAmounts instead of using an inline implementation and no longer imports BudgetData. Tests cover rounding, conversion of monetary fields, preservation of percentage-based values, and proper handling of loan fields. Exported roundCurrency helper is provided for testing.
Move common mono/path display styles into src/components/shared/sharedPathDisplay.css and import it in EncryptionConfigPanel and FileRelinkModal. Apply the .shared-path-display (and .shared-path-display--primary) classes to code elements, update EncryptionConfigPanel selectors to .encryption-key-code, and remove duplicated styling from the component CSS files to keep display styles consistent and DRY.
Delete stale .backup files for BenefitsManager, LoansManager, and shared Button components, and remove the BenefitsManager index export. Also remove mentions of the BenefitsManager component from src/README.md. This cleans up leftover backup artifacts and outdated README references.
Update src/README.md to match a UI component refactor: move SetupWizard and WelcomeScreen under views/, group per-tab features under tabViews/, consolidate dialog components under modals/, rename shared to _shared/, and add SavingsManager. This keeps the README in sync with the new directory structure and component naming conventions.
Introduce centralized constants for menu events and storage keys and refactor code to use them. Adds src/constants/events.ts and src/constants/storage.ts, replaces hard-coded 'menu:*' channels with MENU_EVENTS + menuChannel (and adds sendMenuEvent helper in electron/main.ts), updates preload and types to use typed MenuEventName, and switches app code (App, PlanDashboard, GlossaryTerm, SettingsModal, ThemeContext) to use APP_CUSTOM_EVENTS for custom DOM events. Also consolidates localStorage key usage in FileStorageService and AccountsService to use STORAGE_KEYS/APP_STORAGE_KEYS, updates related tests, and removes duplicated string literals to improve maintainability.
Add a reusable useEncryptionSetupFlow hook to centralize encryption setup state and persistence (key generation, keychain save/delete, and app settings). Refactor EncryptionSetup, PlanDashboard and SetupWizard to use the hook (removing duplicated FileStorageService/KeychainService logic), wire up new helpers (generateKey, saveSelection, canSaveSelection, goBackToSelection, reset) and update hooks/index export. Include unit tests for the hook (useEncryptionSetupFlow.test.ts) covering key generation, save success/failure and missing-key validation.
Move EncryptionSetup and EncryptionConfigPanel into organized locations and update imports for reuse. EncryptionConfigPanel was relocated to components/_shared/workflows and exported via components/_shared; EncryptionSetup view was moved to components/views/EncryptionSetup with a new index export. Import paths in App.tsx, PlanDashboard, SetupWizard and EncryptionSetup internals were updated accordingly, and CSS/shared path references were adjusted. This refactor centralizes the encryption config panel as a shared workflow and cleans up module resolution.
|
✅ Version Update Detected Version has been correctly bumped from |
65 tasks
Replace direct ACCOUNTS_KEY reference with STORAGE_KEYS.accounts in AccountsService.hasAccounts to centralize storage keys. Add a BudgetData type import to PaySettingsModal for type coverage. Update sampleBudget in budgetCurrencyConversion tests to include settings.locale ('en-US') to match updated settings shape.
|
✅ Version Update Detected Version has been correctly bumped from |
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.
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.