Merged
Conversation
Introduce a compact .btn-utility style for low‑emphasis/contextual actions and add a new 'utility' variant to Button props. Implement an optional successText prop that briefly replaces the button label for 2s after click (while still calling onClick), locking the button width to avoid layout shifts. Added local state, refs, timer cleanup, and a click handler to manage the transient success UI and merged inline styles to preserve width.
Add a settings button to the WelcomeScreen that opens the Settings modal. CSS updates position the button in the top-right of the welcome card (.welcome-card set to position: relative and .welcome-settings-btn positioned absolute). Import Settings, track showSettings state, render the button (with aria label) and include the <Settings isOpen={showSettings} onClose=... /> component.
Replace native action buttons with the shared Button component for generating and copying the encryption key (adds variant and successText). Simplify markup by removing the .encryption-key-display wrapper and delete its CSS rules; update the heading to "Your Encryption Key" and slightly reword the alert text for clarity. Import Button from shared and normalize onClick handlers.
Main: add quit-app and reopen-welcome-window ipc handlers and a welcomeWindowIdsPendingReopen set to avoid reopening the welcome window when a window requests a reopen. Introduce getDefaultPlanTransitionBounds to calculate centered plan window bounds with side gaps and use it as a fallback in budgetLoaded when no size is provided. Update welcome window close handling to respect pending-reopen IDs. Change DevTools toggle to target the focused window (fallbacks to main/welcome/first window). Preload: expose quitApp and reopenWelcomeWindow to renderer via contextBridge. App: remove automatic encryption setup check and FileStorageService usage; only show the encryption setup UI when explicitly requested from an active plan (forceSetupAgain && budgetData) and simplify related handlers. Types: add enabled? to RetirementElection and add typings for quitApp and reopenWelcomeWindow in ElectronAPI. These changes enable safer reopen/quit flows, better window sizing behavior during welcome->plan transitions, and simplify the encryption setup UX.
Introduce a demo launch flow with a DEMO_LAUNCH_DELAY_MS and demoLoading state, and combine loading+demoLoading into an isBusy flag to prevent concurrent actions. Move settings and demo controls into a new .welcome-header (CSS updated) using flex layout; make the demo button show a loading state and delay before calling createDemoBudget. Replace the standalone Try Demo large button with a small header action, update various buttons and recent-file interactions to respect isBusy, and tweak the welcome copy. These changes improve UX by preventing overlapping operations and providing feedback while the demo plan is prepared.
Introduce CSS custom properties for button spacing, font size and radius; unify layout (inline-flex, gap, line-height) and adjust selectors (use .btn .btn-icon modifiers). Add responsive variable overrides and convert size variants to use CSS vars. In Button.tsx add BUTTON_SIZE_STYLES and ICON_BUTTON_SIZE_STYLES, always include base 'btn' class and use 'btn-icon' as a modifier, and merge size styles into the inline style (with lockedWidth preserved). Also add .backup copies of the updated CSS and TSX files.
Introduce a suggested leftover-per-paycheck UI and logic to the setup wizard, including styling and responsive CSS. Replace hours-per-pay-period input with hours-per-week and compute hours per pay period using getPaychecksPerYear so hourly users are converted automatically based on pay frequency. Add automatic tax-rate estimation (federal, state, SS, Medicare) applied once when advancing from the tax step, with a flag to avoid reapplying. Update placeholders, helper text, and add an InfoBox to explain starter estimates. Minor copy tweaks for clarity throughout the wizard.
Introduce an accessible MetricCard component and make metric tiles in KeyMetrics clickable/keyboard-navigable (cursor, focus-visible, role/tabIndex, Enter/Space handling). Add navigation callbacks (onNavigateToTaxes/NetPay/Savings/Bills/Remaining) and guard clicks on glossary buttons. Compute and display effectiveTaxRate and remainingShareOfNet values. Update CSS (.metric-card-interactive) for hover/focus styling. Enhance PlanDashboard to support scrolling to a specific position within a tab (top or bottom): add TabScrollPosition type, pendingTabScroll state, scrollTabToPosition helper, and a double requestAnimationFrame effect to perform scrolling after tab activation. Extend openTabFromLink to accept scrollPosition and wire KeyMetrics to open tabs with appropriate scroll options. These changes improve keyboard accessibility and enable navigating directly to specific tab sections.
Introduce app-wide backup and cleanup features: add APP_STORAGE keys/constants and implement FileStorageService.getKnownPlanIds, clearAppMemory, exportAppData, and importAppData. Exports produce a JSON envelope with global preference keys while excluding plan-specific data (e.g. accounts, encryption fields) and stripping sensitive fields from the settings blob; imports validate the envelope and restore only allowed global keys. clearAppMemory removes all app-prefixed keys but preserves unrelated localStorage entries. Also update tests and LocalStorageMock (length and key) to cover plan ID discovery, export/import behavior, clearing app memory, and invalid backup handling.
Introduce a danger zone in Settings with UI and styles to back up, import, and reset local app memory. Adds CSS for the danger section and modal. New state and handlers (backingUp, backedUp, importing, resettingMemory, showResetConfirm) implement file export/import via window.electronAPI and FileStorageService, refresh settings and theme after import, reopen the welcome window, and quit the app after a confirmed reset. Keeps OS keychain entries intact (commented), and provides loading states and confirmations to prevent accidental data loss.
Add visual and functional improvements for retirement plans: new CSS for retirement-type badges (pre/post-tax), disabled item styling, and meta spacing. In TSX, import retirement helpers and use RETIREMENT_PLAN_OPTIONS for the plan select; derive display label with getRetirementPlanDisplayLabel. Add getAccountName helper, sort retirements to prioritize enabled items and by contribution totals, and exclude disabled elections from totals. Preserve/assign enabled state on save and add handleToggleRetirementEnabled plus an enable/disable action button. Misc: switch wording from “Paid” to “Saved”, rename section labels to “Plans”, and show source & tax-type badges in each retirement item.
Treat onboarding/setup plans as not-yet-saveable by detecting incomplete paySettings (salary/hourly) and clearing unsaved-change prompts until setup is finished. Ensure new retirement elections default to enabled (enabled !== false) and ignore elections with enabled === false in contribution calculations (pre-tax, post-tax, and calculateRetirementContributions), preventing disabled elections from affecting totals.
Introduce hintVisibleModes to ViewModeSelector to conditionally show hint text and update multiple components (BillsManager, LoansManager, PayBreakdown, SavingsManager, TaxBreakdown) to only show hints for 'paycheck' mode. Add a suggested leftover-per-paycheck calculation and UI to PaySettingsModal (imports getPaychecksPerYear, new suggestion block, and accompanying CSS). Make assorted UI/UX improvements: compact small buttons in PlanDashboard header/footer, move encryption status into footer, adjust PlanDashboard layout and responsive behavior, refine utility button styles, and improve WelcomeScreen accessibility for recent files (keyboard/focus handling and styles). Minor styling and markup cleanups across components to support these changes.
Extend FileStorageService tests to reject settings-export envelopes when importing/loading budgets and when chosen via open file dialog or relink picker (mocks window.electronAPI loadBudget/openFileDialog). Add retirement.utils tests to verify canonical labels for known plan types, trimmed custom labels and fallback for 'other', and to assert exported RETIREMENT_PLAN_OPTIONS values for UI selectors.
Add detection and UX for budget files moved/renamed on disk. Main changes:
- electron/main: add FS watch logic keyed by window to detect renames by inode/dev, IPC handler ('set-active-budget-file-path') and send 'budget-file-renamed' events to renderer; ensure watchers cleaned up on window close.
- electron/preload & types: expose setActiveBudgetFilePath and onBudgetFileRenamed to renderer.
- PlanDashboard: track missing/renamed active file, prevent saving to stale paths, register active path with main process, handle live rename updates, and show a relink modal to locate moved file. Add related CSS.
- WelcomeScreen: handle missing recent files with a relink modal to locate or remove entries. Add CSS and UI flows.
- FileStorageService: add relinkMovedBudgetFile, inspectBudgetFile, settings-backup detection, improved JSON vs legacy-encrypted parsing, legacy decryption prompt flow, and robust path verification when saving/loading; derive and persist plan name from file path.
- BudgetContext: derive plan name from file path, verify saved file path exists before saving (force Save As if missing), and sync plan name on load.
Overall this implements local rename detection, user-driven relinking of moved files, safer save/load handling for missing or legacy-encrypted files, and UI to surface these actions to users.
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.
Enhance UI components and improve app memory management
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.
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.
Refactor utilities, types, and components for improved organization
|
✅ 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