Skip to content

Commit 9c4e763

Browse files
committed
Extracting the Filter Logic into a custom hook and Cleaning up unused imports.
1 parent d7964fc commit 9c4e763

2 files changed

Lines changed: 138 additions & 274 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { useState, useMemo } from 'react';
2+
import { Subscription, SubscriptionCategory, BillingCycle } from '../types/subscription';
3+
4+
export const useSubscriptionFilters = (subscriptions: Subscription[]) => {
5+
const [searchQuery, setSearchQuery] = useState('');
6+
const [selectedCategories, setSelectedCategories] = useState<SubscriptionCategory[]>([]);
7+
const [selectedBillingCycles, setSelectedBillingCycles] = useState<BillingCycle[]>([]);
8+
const [priceRange, setPriceRange] = useState({ min: 0, max: 1000 });
9+
const [showActiveOnly, setShowActiveOnly] = useState(true);
10+
const [showCryptoOnly, setShowCryptoOnly] = useState(false);
11+
const [sortBy, setSortBy] = useState<'name' | 'price' | 'nextBilling' | 'category'>('name');
12+
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc');
13+
14+
const filteredAndSorted = useMemo(() => {
15+
let filtered = subscriptions || [];
16+
17+
if (searchQuery.trim()) {
18+
filtered = filtered.filter(sub =>
19+
sub.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
20+
sub.description?.toLowerCase().includes(searchQuery.toLowerCase())
21+
);
22+
}
23+
24+
if (selectedCategories.length > 0) {
25+
filtered = filtered.filter(sub => selectedCategories.includes(sub.category));
26+
}
27+
28+
if (selectedBillingCycles.length > 0) {
29+
filtered = filtered.filter(sub => selectedBillingCycles.includes(sub.billingCycle));
30+
}
31+
32+
filtered = filtered.filter(sub => sub.price >= priceRange.min && sub.price <= priceRange.max);
33+
if (showActiveOnly) filtered = filtered.filter(sub => sub.isActive);
34+
if (showCryptoOnly) filtered = filtered.filter(sub => sub.isCryptoEnabled);
35+
36+
return [...filtered].sort((a, b) => {
37+
let comp = 0;
38+
switch (sortBy) {
39+
case 'name': comp = a.name.localeCompare(b.name); break;
40+
case 'price': comp = a.price - b.price; break;
41+
case 'nextBilling': comp = new Date(a.nextBillingDate).getTime() - new Date(b.nextBillingDate).getTime(); break;
42+
case 'category': comp = a.category.localeCompare(b.category); break;
43+
}
44+
return sortOrder === 'asc' ? comp : -comp;
45+
});
46+
}, [subscriptions, searchQuery, selectedCategories, selectedBillingCycles, priceRange, showActiveOnly, showCryptoOnly, sortBy, sortOrder]);
47+
48+
const activeFilterCount = useMemo(() => {
49+
let count = 0;
50+
if (searchQuery.trim()) count++;
51+
if (selectedCategories.length > 0) count++;
52+
if (selectedBillingCycles.length > 0) count++;
53+
if (priceRange.min > 0 || priceRange.max < 1000) count++;
54+
if (!showActiveOnly) count++;
55+
if (showCryptoOnly) count++;
56+
if (sortBy !== 'name' || sortOrder !== 'asc') count++;
57+
return count;
58+
}, [searchQuery, selectedCategories, selectedBillingCycles, priceRange, showActiveOnly, showCryptoOnly, sortBy, sortOrder]);
59+
60+
return {
61+
filters: {
62+
searchQuery, setSearchQuery,
63+
selectedCategories, setSelectedCategories,
64+
selectedBillingCycles, setSelectedBillingCycles,
65+
priceRange, setPriceRange,
66+
showActiveOnly, setShowActiveOnly,
67+
showCryptoOnly, setShowCryptoOnly,
68+
sortBy, setSortBy,
69+
sortOrder, setSortOrder,
70+
},
71+
filteredAndSorted,
72+
activeFilterCount,
73+
hasActiveFilters: activeFilterCount > 0,
74+
clearAllFilters: () => {
75+
setSearchQuery('');
76+
setSelectedCategories([]);
77+
setSelectedBillingCycles([]);
78+
setPriceRange({ min: 0, max: 1000 });
79+
setShowActiveOnly(true);
80+
setShowCryptoOnly(false);
81+
setSortBy('name');
82+
setSortOrder('asc');
83+
}
84+
};
85+
};

0 commit comments

Comments
 (0)