1- import { useCallback , useEffect , useMemo , useReducer , useRef } from "react" ;
1+ import { useCallback , useEffect , useMemo , useRef , useState } from "react" ;
22import type {
33 BuildQueryVariables ,
44 CollectionControl ,
@@ -16,80 +16,6 @@ import type {
1616} from "@/types/collection" ;
1717import { useCursorPagination } from "./use-cursor-pagination" ;
1818
19- // -----------------------------------------------------------------------------
20- // Reducer
21- // -----------------------------------------------------------------------------
22-
23- interface CollectionState {
24- filters : Filter [ ] ;
25- sortStates : SortState [ ] ;
26- pageSize : number ;
27- }
28-
29- type CollectionAction =
30- | {
31- type : "ADD_FILTER" ;
32- field : string ;
33- operator : string ;
34- value : unknown ;
35- caseSensitive ?: boolean ;
36- }
37- | { type : "SET_FILTERS" ; filters : Filter [ ] }
38- | { type : "REMOVE_FILTER" ; field : string }
39- | { type : "CLEAR_FILTERS" }
40- | { type : "SET_SORT" ; field : string ; direction ?: "Asc" | "Desc" }
41- | { type : "CLEAR_SORT" }
42- | { type : "SET_PAGE_SIZE" ; pageSize : number } ;
43-
44- function collectionReducer ( state : CollectionState , action : CollectionAction ) : CollectionState {
45- switch ( action . type ) {
46- case "ADD_FILTER" : {
47- const { field, operator, value, caseSensitive } = action ;
48- const newFilter : Filter = {
49- field,
50- operator : operator as Filter [ "operator" ] ,
51- value,
52- caseSensitive,
53- } ;
54- const existing = state . filters . findIndex ( ( f ) => f . field === field ) ;
55- const filters =
56- existing >= 0
57- ? state . filters . map ( ( f , i ) => ( i === existing ? newFilter : f ) )
58- : [ ...state . filters , newFilter ] ;
59- return { ...state , filters } ;
60- }
61- case "SET_FILTERS" :
62- return { ...state , filters : action . filters } ;
63- case "REMOVE_FILTER" :
64- return {
65- ...state ,
66- filters : state . filters . filter ( ( f ) => f . field !== action . field ) ,
67- } ;
68- case "CLEAR_FILTERS" :
69- return { ...state , filters : [ ] } ;
70- case "SET_SORT" : {
71- const { field, direction } = action ;
72- if ( direction === undefined ) {
73- return {
74- ...state ,
75- sortStates : state . sortStates . filter ( ( s ) => s . field !== field ) ,
76- } ;
77- }
78- const filtered = state . sortStates . filter ( ( s ) => s . field !== field ) ;
79- return {
80- ...state ,
81- sortStates : [ ...filtered , { field, direction } ] ,
82- } ;
83- }
84- case "CLEAR_SORT" :
85- return { ...state , sortStates : [ ] } ;
86- case "SET_PAGE_SIZE" :
87- return { ...state , pageSize : action . pageSize } ;
88- default :
89- return state ;
90- }
91- }
92-
9319// -----------------------------------------------------------------------------
9420// Case-insensitive regex conversion helpers
9521// -----------------------------------------------------------------------------
@@ -208,52 +134,48 @@ export function useCollectionVariables(
208134 const { initialFilters = [ ] , initialSort = [ ] , pageSize : initialPageSize = 20 } = params ;
209135
210136 // ---------------------------------------------------------------------------
211- // State (reducer-based )
137+ // Persistence read (once on mount )
212138 // ---------------------------------------------------------------------------
213- const [ state , dispatch ] = useReducer ( collectionReducer , undefined , ( ) => {
214- const snapshot = persistence ?. read ( ) ;
215- return {
216- filters : snapshot ?. filters ?? initialFilters ,
217- sortStates : snapshot ?. sort ?? initialSort ,
218- pageSize : snapshot ?. pageSize ?? initialPageSize ,
219- } ;
220- } ) ;
221-
222- const { filters, sortStates, pageSize } = state ;
139+ const [ snapshot ] = useState ( ( ) => persistence ?. read ( ) ) ;
223140
224141 // ---------------------------------------------------------------------------
225- // Persistence write-back (skip initial render)
142+ // State
226143 // ---------------------------------------------------------------------------
227- const isFirstRenderRef = useRef ( true ) ;
228- useEffect ( ( ) => {
229- if ( isFirstRenderRef . current ) {
230- isFirstRenderRef . current = false ;
231- return ;
232- }
233- persistence ?. write ( {
234- filters : state . filters ,
235- sort : state . sortStates ,
236- pageSize : state . pageSize ,
237- } ) ;
238- } , [ state . filters , state . sortStates , state . pageSize , persistence ] ) ;
144+ const [ filters , setFiltersState ] = useState < Filter [ ] > ( snapshot ?. filters ?? initialFilters ) ;
145+ const [ sortStates , setSortStates ] = useState < SortState [ ] > ( snapshot ?. sort ?? initialSort ) ;
239146
240- // ---------------------------------------------------------------------------
241- // Cursor pagination (pageSize owned by reducer, passed in)
242- // ---------------------------------------------------------------------------
243147 const {
148+ pageSize,
244149 paginationVariables,
245150 goToNextPage,
246151 goToPrevPage,
247152 resetPage,
248153 goToFirstPage,
249154 goToLastPage,
155+ setPageSize : setCursorPageSize ,
250156 getHasPrevPage,
251157 getHasNextPage,
252158 resetCount,
253- } = useCursorPagination ( pageSize ) ;
159+ } = useCursorPagination ( snapshot ?. pageSize ?? initialPageSize ) ;
254160
255161 // ---------------------------------------------------------------------------
256- // Control actions (dispatch user actions + reset pagination)
162+ // Persistence write-back (skip initial render)
163+ // ---------------------------------------------------------------------------
164+ const isFirstRenderRef = useRef ( true ) ;
165+ useEffect ( ( ) => {
166+ if ( isFirstRenderRef . current ) {
167+ isFirstRenderRef . current = false ;
168+ return ;
169+ }
170+ persistence ?. write ( {
171+ filters,
172+ sort : sortStates ,
173+ pageSize,
174+ } ) ;
175+ } , [ filters , sortStates , pageSize , persistence ] ) ;
176+
177+ // ---------------------------------------------------------------------------
178+ // Filter operations
257179 // ---------------------------------------------------------------------------
258180 const addFilter = useCallback (
259181 (
@@ -262,12 +184,20 @@ export function useCollectionVariables(
262184 value : unknown ,
263185 filterOptions ?: { caseSensitive ?: boolean } ,
264186 ) => {
265- dispatch ( {
266- type : "ADD_FILTER" ,
267- field,
268- operator,
269- value,
270- caseSensitive : filterOptions ?. caseSensitive ,
187+ setFiltersState ( ( prev ) => {
188+ const existing = prev . findIndex ( ( f ) => f . field === field ) ;
189+ const newFilter : Filter = {
190+ field,
191+ operator,
192+ value,
193+ caseSensitive : filterOptions ?. caseSensitive ,
194+ } ;
195+ if ( existing >= 0 ) {
196+ const updated = [ ...prev ] ;
197+ updated [ existing ] = newFilter ;
198+ return updated ;
199+ }
200+ return [ ...prev , newFilter ] ;
271201 } ) ;
272202 resetPage ( ) ;
273203 } ,
@@ -276,44 +206,53 @@ export function useCollectionVariables(
276206
277207 const setFilters = useCallback (
278208 ( newFilters : Filter [ ] ) => {
279- dispatch ( { type : "SET_FILTERS" , filters : newFilters } ) ;
209+ setFiltersState ( newFilters ) ;
280210 resetPage ( ) ;
281211 } ,
282212 [ resetPage ] ,
283213 ) ;
284214
285215 const removeFilter = useCallback (
286216 ( field : string ) => {
287- dispatch ( { type : "REMOVE_FILTER" , field } ) ;
217+ setFiltersState ( ( prev ) => prev . filter ( ( f ) => f . field !== field ) ) ;
288218 resetPage ( ) ;
289219 } ,
290220 [ resetPage ] ,
291221 ) ;
292222
293223 const clearFilters = useCallback ( ( ) => {
294- dispatch ( { type : "CLEAR_FILTERS" } ) ;
224+ setFiltersState ( [ ] ) ;
295225 resetPage ( ) ;
296226 } , [ resetPage ] ) ;
297227
228+ // ---------------------------------------------------------------------------
229+ // Sort operations
230+ // ---------------------------------------------------------------------------
298231 const setSort = useCallback (
299232 ( field : string , direction ?: "Asc" | "Desc" ) => {
300- dispatch ( { type : "SET_SORT" , field, direction } ) ;
233+ setSortStates ( ( prev ) => {
234+ if ( direction === undefined ) {
235+ return prev . filter ( ( s ) => s . field !== field ) ;
236+ }
237+ const newState : SortState = { field, direction } ;
238+ const filtered = prev . filter ( ( s ) => s . field !== field ) ;
239+ return [ ...filtered , newState ] ;
240+ } ) ;
301241 resetPage ( ) ;
302242 } ,
303243 [ resetPage ] ,
304244 ) ;
305245
306246 const clearSort = useCallback ( ( ) => {
307- dispatch ( { type : "CLEAR_SORT" } ) ;
247+ setSortStates ( [ ] ) ;
308248 resetPage ( ) ;
309249 } , [ resetPage ] ) ;
310250
311251 const setPageSize = useCallback (
312252 ( size : number ) => {
313- dispatch ( { type : "SET_PAGE_SIZE" , pageSize : size } ) ;
314- resetPage ( ) ;
253+ setCursorPageSize ( size ) ;
315254 } ,
316- [ resetPage ] ,
255+ [ setCursorPageSize ] ,
317256 ) ;
318257
319258 // ---------------------------------------------------------------------------
0 commit comments