forked from Disciplr-Org/Disciplr-Frontend
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathvaultFilter.ts
More file actions
105 lines (92 loc) · 2.67 KB
/
Copy pathvaultFilter.ts
File metadata and controls
105 lines (92 loc) · 2.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/**
* vaultFilter.ts
*
* Pure functions for filtering and sorting vault lists.
* Extracted for unit-testability in isolation from React components.
*/
import type { Vault, VaultStatus } from '../types/vault';
/**
* Filter options for vault list.
*/
export interface VaultFilterOptions {
/** Status to filter by; undefined or 'all' returns all statuses */
status?: VaultStatus | 'all';
/** Search query to match against vault name (case-insensitive) */
query?: string;
}
/**
* Sort options for vault list.
*/
export interface VaultSortOptions {
/** Field to sort by */
by: 'deadline' | 'amount';
/** Sort direction: 'asc' for ascending, 'desc' for descending */
dir: 'asc' | 'desc';
}
/**
* Filters vaults by status and/or name search query.
*
* @param vaults - Array of vaults to filter
* @param options - Filter options (status, query)
* @returns Filtered array of vaults (new array, does not mutate input)
*
* @example
* filterVaults(vaults, { status: 'active', query: 'alpha' })
*/
export function filterVaults(
vaults: Vault[],
options: VaultFilterOptions = {},
): Vault[] {
const { status, query = '' } = options;
const normalizedQuery = query.trim().toLowerCase();
// Whitespace-only query should return empty results
if (query && !normalizedQuery) {
return [];
}
return vaults.filter((vault) => {
// Filter by status if provided (and not 'all')
if (status && status !== 'all' && vault.status !== status) {
return false;
}
// Filter by search query if provided (case-insensitive match on name)
if (normalizedQuery) {
const nameMatch = vault.name.toLowerCase().includes(normalizedQuery);
if (!nameMatch) {
return false;
}
}
return true;
});
}
/**
* Sorts vaults by deadline or amount.
*
* @param vaults - Array of vaults to sort
* @param options - Sort options (by, dir)
* @returns Sorted array of vaults (new array, does not mutate input)
*
* @example
* sortVaults(vaults, { by: 'deadline', dir: 'asc' })
*/
export function sortVaults(
vaults: Vault[],
options: VaultSortOptions,
): Vault[] {
const { by, dir } = options;
const multiplier = dir === 'asc' ? 1 : -1;
return [...vaults].sort((a, b) => {
let comparison = 0;
if (by === 'deadline') {
const dateA = new Date(a.deadline).getTime();
const dateB = new Date(b.deadline).getTime();
comparison = dateA - dateB;
} else if (by === 'amount') {
comparison = a.amount - b.amount;
}
// Stable sort: use id as tiebreaker to maintain consistent ordering
if (comparison === 0) {
return a.id.localeCompare(b.id) * multiplier;
}
return comparison * multiplier;
});
}