11import styles from "./styles.module.css"
2- import { useState , useEffect } from "react"
32import type { ChangelogItem } from "~/components/ChangelogSnippet/types.ts"
4- import { matchesFilters } from "~/utils/changelogFilters.ts"
5- import { parseURLParams , updateFilterURL , toggleItemInArray } from "~/utils/changelogFilterUtils.ts"
63import { DesktopFilters } from "./DesktopFilters.tsx"
74import { MobileFilters } from "./MobileFilters.tsx"
85
@@ -14,207 +11,13 @@ export interface ChangelogFiltersProps {
1411}
1512
1613export const ChangelogFilters = ( { products, networks, types, items } : ChangelogFiltersProps ) => {
17- const [ searchExpanded , setSearchExpanded ] = useState ( false )
18- const [ searchTerm , setSearchTerm ] = useState ( "" )
19- const [ selectedProducts , setSelectedProducts ] = useState < string [ ] > ( [ ] )
20- const [ selectedNetworks , setSelectedNetworks ] = useState < string [ ] > ( [ ] )
21- const [ selectedTypes , setSelectedTypes ] = useState < string [ ] > ( [ ] )
22-
23- // Read URL parameters on mount
24- useEffect ( ( ) => {
25- const urlParams = parseURLParams ( )
26-
27- setSelectedProducts ( urlParams . products )
28- setSelectedNetworks ( urlParams . networks )
29- setSelectedTypes ( urlParams . types )
30- setSearchTerm ( urlParams . searchTerm )
31- setSearchExpanded ( urlParams . searchExpanded )
32- } , [ ] )
33-
34- // Update URL when filters change
35- useEffect ( ( ) => {
36- updateFilterURL ( selectedProducts , selectedNetworks , selectedTypes , searchTerm )
37- } , [ selectedProducts , selectedNetworks , selectedTypes , searchTerm ] )
38-
39- // Filter items and update the display
40- useEffect ( ( ) => {
41- if ( typeof window === "undefined" ) return
42-
43- const changelogItems = document . querySelectorAll ( ".changelog-item" )
44- const loadMoreSection = document . querySelector ( ".load-more-section" ) as HTMLElement
45- const visibleCountSpan = document . getElementById ( "visible-count" )
46- const emptyState = document . querySelector ( ".empty-state" ) as HTMLElement
47- const changelogList = document . querySelector ( ".changelog-list" ) as HTMLElement
48-
49- if ( searchTerm ) {
50- // Search takes priority - filter by search term
51- const searchLower = searchTerm . toLowerCase ( )
52- let visibleCount = 0
53-
54- changelogItems . forEach ( ( item ) => {
55- const index = parseInt ( item . getAttribute ( "data-index" ) || "0" )
56- const changelogItem = items [ index ]
57-
58- const matchesSearch =
59- changelogItem ?. name . toLowerCase ( ) . includes ( searchLower ) ||
60- changelogItem ?. [ "text-description" ] ?. toLowerCase ( ) . includes ( searchLower )
61-
62- if ( matchesSearch ) {
63- ; ( item as HTMLElement ) . style . display = ""
64- visibleCount ++
65- } else {
66- ; ( item as HTMLElement ) . style . display = "none"
67- }
68- } )
69-
70- // Hide load more section when searching
71- if ( loadMoreSection ) {
72- loadMoreSection . style . display = "none"
73- }
74-
75- // Show/hide empty state
76- if ( emptyState && changelogList ) {
77- if ( visibleCount === 0 ) {
78- emptyState . style . display = "flex"
79- changelogList . style . display = "none"
80- } else {
81- emptyState . style . display = "none"
82- changelogList . style . display = "flex"
83- }
84- }
85- } else {
86- // Apply filter logic
87- let visibleCount = 0
88- const hasFilters = selectedProducts . length > 0 || selectedNetworks . length > 0 || selectedTypes . length > 0
89-
90- changelogItems . forEach ( ( item ) => {
91- const index = parseInt ( item . getAttribute ( "data-index" ) || "0" )
92- const changelogItem = items [ index ]
93-
94- if ( hasFilters && changelogItem ) {
95- const matches = matchesFilters ( changelogItem , selectedProducts , selectedNetworks , selectedTypes )
96- if ( matches ) {
97- ; ( item as HTMLElement ) . style . display = ""
98- visibleCount ++
99- } else {
100- ; ( item as HTMLElement ) . style . display = "none"
101- }
102- } else {
103- // No filters - show first 25 items by default
104- if ( visibleCount < 25 ) {
105- ; ( item as HTMLElement ) . style . display = ""
106- visibleCount ++
107- } else {
108- ; ( item as HTMLElement ) . style . display = "none"
109- }
110- }
111- } )
112-
113- // Show/hide load more section based on filters
114- if ( loadMoreSection ) {
115- if ( hasFilters ) {
116- loadMoreSection . style . display = "none"
117- } else {
118- loadMoreSection . style . display = visibleCount >= items . length ? "none" : "flex"
119- }
120- }
121-
122- // Update visible count
123- if ( visibleCountSpan ) {
124- visibleCountSpan . textContent = visibleCount . toString ( )
125- }
126-
127- // Show/hide empty state
128- if ( emptyState && changelogList ) {
129- if ( hasFilters && visibleCount === 0 ) {
130- emptyState . style . display = "flex"
131- changelogList . style . display = "none"
132- } else {
133- emptyState . style . display = "none"
134- changelogList . style . display = "flex"
135- }
136- }
137- }
138- } , [ searchTerm , selectedProducts , selectedNetworks , selectedTypes , items ] )
139-
140- const handleSearchChange = ( value : string ) => {
141- setSearchTerm ( value )
142- }
143-
144- const handleSearchToggle = ( expanded : boolean ) => {
145- setSearchExpanded ( expanded )
146- }
147-
148- const toggleSelection = ( type : "product" | "network" | "type" , value : string ) => {
149- switch ( type ) {
150- case "product" :
151- setSelectedProducts ( ( prev ) => toggleItemInArray ( prev , value ) )
152- break
153- case "network" :
154- setSelectedNetworks ( ( prev ) => toggleItemInArray ( prev , value ) )
155- break
156- case "type" :
157- setSelectedTypes ( ( prev ) => toggleItemInArray ( prev , value ) )
158- break
159- }
160- }
161-
162- const clearProductFilters = ( ) => {
163- setSelectedProducts ( [ ] )
164- }
165-
166- const clearNetworkFilters = ( ) => {
167- setSelectedNetworks ( [ ] )
168- }
169-
170- const clearTypeFilters = ( ) => {
171- setSelectedTypes ( [ ] )
172- }
173-
174- const clearAllFilters = ( ) => {
175- setSelectedProducts ( [ ] )
176- setSelectedNetworks ( [ ] )
177- setSelectedTypes ( [ ] )
178- }
179-
18014 return (
18115 < div className = { styles . wrapper } >
18216 < div className = { styles . desktopFilters } >
183- < DesktopFilters
184- products = { products }
185- networks = { networks }
186- types = { types }
187- selectedProducts = { selectedProducts }
188- selectedNetworks = { selectedNetworks }
189- selectedTypes = { selectedTypes }
190- onToggleSelection = { toggleSelection }
191- onClearProducts = { clearProductFilters }
192- onClearNetworks = { clearNetworkFilters }
193- onClearTypes = { clearTypeFilters }
194- searchTerm = { searchTerm }
195- searchExpanded = { searchExpanded }
196- onSearchChange = { handleSearchChange }
197- onSearchToggle = { handleSearchToggle }
198- />
17+ < DesktopFilters products = { products } networks = { networks } types = { types } items = { items } />
19918 </ div >
20019 < div className = { styles . mobileFilters } >
201- < MobileFilters
202- products = { products }
203- networks = { networks }
204- types = { types }
205- selectedProducts = { selectedProducts }
206- selectedNetworks = { selectedNetworks }
207- selectedTypes = { selectedTypes }
208- onToggleSelection = { toggleSelection }
209- onClearProducts = { clearProductFilters }
210- onClearNetworks = { clearNetworkFilters }
211- onClearTypes = { clearTypeFilters }
212- onClearAll = { clearAllFilters }
213- searchTerm = { searchTerm }
214- searchExpanded = { searchExpanded }
215- onSearchChange = { handleSearchChange }
216- onSearchToggle = { handleSearchToggle }
217- />
20+ < MobileFilters products = { products } networks = { networks } types = { types } items = { items } />
21821 </ div >
21922 </ div >
22023 )
0 commit comments