Skip to content

Commit 2d6a134

Browse files
authored
Feature/close account (#293)
* Implement account closure feature with UI updates and tests * Refactor AppHeader and NavItem styles for improved layout; update MonthOverviewSummary to display formatted date * Refactor AppHeader and NavItem styles for consistency and improved UI responsiveness * Add unit tests for account balance summary and transaction totals; refactor related hooks for improved calculations * Update @luca-financial/luca-schema dependency to version 3.1.0 in package.json and pnpm-lock.yaml * Refactor account type handling and improve balance summary calculations; add support for new account types and enhance utility functions * Enhance transaction categorization and summary calculations; add credit card expense tracking and improve dashboard metrics display * Refactor transaction handling and metrics; enhance credit card payment tracking and update dashboard components for improved financial overview * Implement dashboard analytics filters and enhance account balance summary calculations; add filtering utilities for transactions and accounts * Update default state for excluding closed accounts in Dashboard component * Enhance dashboard filters and account balance calculations; add support for escrow accounts and improve transaction handling * Refactor transaction handling in dashboard components; update test cases and improve month-end projections logic * Enhance transaction totals calculations and projections; add income and credits handling, and refactor dashboard components for improved financial overview * Add combined dashboard balances calculation and update dashboard components for improved financial metrics * Bump version to 2.8.0 in package.json * Refactor dashboard metrics and transaction totals calculations; enhance balance handling and credit card metrics * Refactor net flow calculations in transaction totals; ensure accurate income and expense handling * Refactor transaction totals calculations; introduce cash credits and outflows handling for improved financial metrics * Refactor income and expense metrics labels and variables for clarity; update related calculations in MonthOverviewSummary * Enhance tooltip functionality for financial metrics; add detailed tooltips for income, expenses, and balances in MonthOverviewSummary * Update tooltips in MonthOverviewSummary to clarify account types; replace 'non-credit-card' with 'asset' for consistency. * Refactor DetailedComparisonTable to use sections for improved organization; update metrics and tooltips for clarity. * Refactor DetailedComparisonTable layout and improve metric labels for clarity; update tooltip descriptions for consistency. * Update sync button to use aria-label for improved accessibility * Enhance DetailedComparisonTable with new metrics and improved styling; add icons for better visual representation of income and expenses. * Refactor DetailedComparisonTable to ensure consistent styling for total rows; adjust height and box-sizing properties. * Remove unused MonthlyIncomeExpenseCards, RecentActivitySection, and UpcomingActivitySection components * Refactor MonthOverviewSummary component and related utilities - Simplified MonthOverviewSummary by extracting utility functions and components. - Created OverviewPeriodCard for rendering period-specific metrics. - Introduced TooltipValue component for consistent tooltip rendering. - Moved metric-related utility functions to monthOverviewSummaryUtils.js. - Updated detailed comparison sections to use new utility functions for better readability and maintainability. * feat: add Spending History Section components and hooks - Implement SpendingHistorySummaryCards for displaying summary of spending by state and totals. - Create SpendingHistoryTable for detailed transaction view with expandable categories and subcategories. - Introduce TransactionDetailTable for displaying individual transaction details. - Add utility functions and constants for formatting and managing spending data. - Implement hooks for managing state and data in the Spending History Section. * feat: refactor DetailedComparisonTable to use DetailedComparisonValueCell for improved readability and maintainability * refactor: clean up formatting and import statements in DetailedComparisonTable component * refactor: simplify DashboardAnalyticsFilters by removing unused includedCount calculation and improving layout * feat: enhance MetricCell and MonthOverviewSummary to support icons and absolute value display * feat: update SpendingPeriodControls and SpendingHistorySection for improved label handling and default selection * feat: update @luca-financial/luca-schema dependency to version 3.2.0 * refactor: remove commented-out BalanceRow component from AccountCard * feat: add account closure support and enhance dashboard analytics for closed accounts
1 parent ce5a10b commit 2d6a134

55 files changed

Lines changed: 3887 additions & 2172 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [2.8.0] - 2026-04-04
11+
12+
### Added
13+
14+
- Added account closure support across the app, including closed-account state persistence, account-card/status updates, and a dedicated closed-account row in the ledger.
15+
- Added dashboard analytics filters for excluding closed accounts by default and temporarily including or excluding individual accounts from dashboard calculations.
16+
- Added a detailed Current Month Overview breakdown with current, remaining, and month-end comparisons for income, expenses, balances, and credit card activity, including metric tooltips and a grouped comparison table.
17+
18+
### Changed
19+
20+
- Updated dashboard balance and projection calculations to better separate asset-account balances from credit card balances, support credit card payments/credits/charges explicitly, and account for newer schema-driven account types.
21+
- Switched account-type pickers and related account utilities to use schema-exported account type enums, including support for recently added types such as cash and escrow.
22+
- Refactored the dashboard overview and categorized-spending sections into smaller reusable components, and removed the legacy dashboard Recent Activity, Upcoming Activity, and old monthly summary cards.
23+
- Updated categorized-spending controls on the dashboard to default to the current month and polished the shared month/year selector behavior and spacing.
24+
- Bumped application version to `2.8.0`. (#293)
25+
26+
### Fixed
27+
28+
- Fixed dashboard account inclusion behavior so closed and escrow accounts can be excluded by default without preventing users from re-including them for the current session.
29+
- Fixed dashboard credit card balance aggregation to use the combined signed balance of included credit card accounts.
30+
- Fixed ledger sync-button tooltip warnings caused by passing a `title` prop to a tooltip child.
31+
1032
## [2.7.0] - 2026-04-03
1133

1234
### Added

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "luca-ledger",
3-
"version": "2.7.0",
3+
"version": "2.8.0",
44
"homepage": "https://lucaledger.app/",
55
"type": "module",
66
"license": "MIT",
@@ -19,7 +19,7 @@
1919
"dependencies": {
2020
"@emotion/react": "^11.14.0",
2121
"@emotion/styled": "^11.14.1",
22-
"@luca-financial/luca-schema": "^3.0.3",
22+
"@luca-financial/luca-schema": "^3.2.0",
2323
"@mui/icons-material": "^7.3.9",
2424
"@mui/material": "^7.3.9",
2525
"@mui/system": "^7.3.9",

pnpm-lock.yaml

Lines changed: 17 additions & 17 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/__tests__/components/LedgerTable.test.jsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import {
99
endOfMonth,
1010
} from 'date-fns';
1111

12+
import { getAccountClosedRowContent } from '@/components/LedgerTable/utils';
13+
1214
describe('LedgerTable Year Filter', () => {
1315
it('should filter transactions by selected year', () => {
1416
// Mock transactions from different years
@@ -173,4 +175,20 @@ describe('LedgerTable Year Filter', () => {
173175
expect(filtered).toHaveLength(4);
174176
expect(filtered.map((t) => t.id)).toEqual(['2', '3', '4', '5']);
175177
});
178+
179+
it('should build closed account row content with the closure date', () => {
180+
expect(
181+
getAccountClosedRowContent('2025-02-14T12:00:00.000Z'),
182+
).toEqual({
183+
label: 'ACCOUNT CLOSED',
184+
detail: 'Feb 14, 2025',
185+
});
186+
});
187+
188+
it('should build closed account row content without a detail for missing dates', () => {
189+
expect(getAccountClosedRowContent(null)).toEqual({
190+
label: 'ACCOUNT CLOSED',
191+
detail: null,
192+
});
193+
});
176194
});
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { AccountType } from '@/store/accounts/constants';
4+
import { TransactionStateEnum } from '@/store/transactions/constants';
5+
import { buildAccountBalanceSummary } from '@/hooks/useAccountBalances';
6+
7+
describe('buildAccountBalanceSummary', () => {
8+
it('uses completed transactions for the current combined non-credit-card balance', () => {
9+
const accounts = [
10+
{ id: 'checking-1', type: AccountType.CHECKING },
11+
{ id: 'savings-1', type: AccountType.SAVINGS },
12+
{ id: 'cash-1', type: AccountType.CASH },
13+
{ id: 'escrow-1', type: AccountType.ESCROW },
14+
{ id: 'external-1', type: AccountType.EXTERNAL },
15+
{ id: 'credit-1', type: AccountType.CREDIT_CARD },
16+
{ id: 'credit-2', type: AccountType.CREDIT_CARD },
17+
];
18+
19+
const transactions = [
20+
{
21+
id: 'tx-1',
22+
accountId: 'checking-1',
23+
amount: 50000,
24+
transactionState: TransactionStateEnum.COMPLETED,
25+
},
26+
{
27+
id: 'tx-2',
28+
accountId: 'checking-1',
29+
amount: -12000,
30+
transactionState: TransactionStateEnum.COMPLETED,
31+
},
32+
{
33+
id: 'tx-3',
34+
accountId: 'savings-1',
35+
amount: 8000,
36+
transactionState: TransactionStateEnum.COMPLETED,
37+
},
38+
{
39+
id: 'tx-4',
40+
accountId: 'cash-1',
41+
amount: 2500,
42+
transactionState: TransactionStateEnum.COMPLETED,
43+
},
44+
{
45+
id: 'tx-5',
46+
accountId: 'escrow-1',
47+
amount: 20000,
48+
transactionState: TransactionStateEnum.COMPLETED,
49+
},
50+
{
51+
id: 'tx-6',
52+
accountId: 'external-1',
53+
amount: 100000,
54+
transactionState: TransactionStateEnum.COMPLETED,
55+
},
56+
{
57+
id: 'tx-7',
58+
accountId: 'checking-1',
59+
amount: -3000,
60+
transactionState: TransactionStateEnum.PENDING,
61+
},
62+
{
63+
id: 'tx-8',
64+
accountId: 'credit-1',
65+
amount: 10000,
66+
transactionState: TransactionStateEnum.COMPLETED,
67+
},
68+
{
69+
id: 'tx-9',
70+
accountId: 'credit-2',
71+
amount: -2500,
72+
transactionState: TransactionStateEnum.COMPLETED,
73+
},
74+
];
75+
76+
const summary = buildAccountBalanceSummary(accounts, transactions);
77+
78+
expect(summary.totals.current).toBe(168500);
79+
expect(summary.totals.pending).toBe(165500);
80+
expect(summary.creditCardTotals.current).toBe(7500);
81+
});
82+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { AccountType, AccountTypeOptions } from '@/store/accounts/constants';
4+
import {
5+
formatAccountClosedAt,
6+
formatAccountType,
7+
isCreditCardAccountType,
8+
isAccountClosed,
9+
isIncludedInBalanceTotals,
10+
sortAccountTypes,
11+
} from '@/store/accounts/utils';
12+
13+
describe('account utils', () => {
14+
it('treats accounts with a closedAt timestamp as closed', () => {
15+
expect(isAccountClosed({ closedAt: '2025-02-14T00:00:00.000Z' })).toBe(
16+
true,
17+
);
18+
});
19+
20+
it('treats accounts without a closedAt timestamp as open', () => {
21+
expect(isAccountClosed({ closedAt: null })).toBe(false);
22+
expect(isAccountClosed({})).toBe(false);
23+
});
24+
25+
it('formats closedAt dates for UI display', () => {
26+
expect(formatAccountClosedAt('2025-02-14T12:00:00.000Z')).toBe(
27+
'Feb 14, 2025',
28+
);
29+
});
30+
31+
it('returns null for missing or invalid closedAt dates', () => {
32+
expect(formatAccountClosedAt(null)).toBeNull();
33+
expect(formatAccountClosedAt('not-a-date')).toBeNull();
34+
});
35+
36+
it('formats account types for display', () => {
37+
expect(formatAccountType(AccountType.CREDIT_CARD)).toBe('Credit Card');
38+
expect(formatAccountType(AccountType.ESCROW)).toBe('Escrow');
39+
});
40+
41+
it('sorts account types by their display label', () => {
42+
expect(
43+
sortAccountTypes([
44+
AccountType.ESCROW,
45+
AccountType.CREDIT_CARD,
46+
AccountType.CASH,
47+
]),
48+
).toEqual([AccountType.CASH, AccountType.CREDIT_CARD, AccountType.ESCROW]);
49+
});
50+
51+
it('exposes account types from the shared schema enum', () => {
52+
expect(AccountTypeOptions).toContain(AccountType.CASH);
53+
expect(AccountTypeOptions).toContain(AccountType.ESCROW);
54+
});
55+
56+
it('only includes liquid cash account types in dashboard balance totals', () => {
57+
expect(isIncludedInBalanceTotals(AccountType.CHECKING)).toBe(true);
58+
expect(isIncludedInBalanceTotals(AccountType.SAVINGS)).toBe(true);
59+
expect(isIncludedInBalanceTotals(AccountType.CASH)).toBe(true);
60+
expect(isIncludedInBalanceTotals(AccountType.ESCROW)).toBe(false);
61+
expect(isIncludedInBalanceTotals(AccountType.EXTERNAL)).toBe(false);
62+
expect(isIncludedInBalanceTotals(AccountType.CREDIT_CARD)).toBe(false);
63+
expect(isCreditCardAccountType(AccountType.CREDIT_CARD)).toBe(true);
64+
});
65+
});

src/__tests__/store/accountsSlice.test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,23 @@ describe('Accounts Slice', () => {
119119
expect(state.data[0].name).toBe('Updated Name');
120120
});
121121

122+
it('should persist a valid closedAt value', () => {
123+
const stateWithData = {
124+
...initialState,
125+
data: [validCheckingAccount],
126+
};
127+
const closedAccount = {
128+
...validCheckingAccount,
129+
closedAt: '2025-02-14T00:00:00.000Z',
130+
};
131+
const state = accountsReducer(
132+
stateWithData,
133+
updateAccount(closedAccount),
134+
);
135+
136+
expect(state.data[0].closedAt).toBe('2025-02-14T00:00:00.000Z');
137+
});
138+
122139
it('should not modify other accounts', () => {
123140
const stateWithData = {
124141
...initialState,

0 commit comments

Comments
 (0)