@@ -78,6 +78,43 @@ describe('filters store - filter business rules', () => {
7878 useFiltersStore = module . useFiltersStore
7979 } )
8080
81+ describe ( 'business rule: state should be initialised from PHP initial state using files_list_filter_* keys' , ( ) => {
82+ beforeEach ( ( ) => {
83+ vi . resetModules ( )
84+ } )
85+
86+ it ( 'reads filter_status from files_list_filter_status key' , async ( ) => {
87+ const loadStateMock = loadState as MockedFunction < typeof loadState >
88+ loadStateMock . mockReturnValue ( { files_list_filter_status : '["signed"]' , files_list_filter_modified : '' } )
89+
90+ const { useFiltersStore : freshStore } = await import ( '../../store/filters.js' )
91+ const store = freshStore ( )
92+
93+ expect ( store . filter_status ) . toBe ( '["signed"]' )
94+ } )
95+
96+ it ( 'reads filter_modified from files_list_filter_modified key' , async ( ) => {
97+ const loadStateMock = loadState as MockedFunction < typeof loadState >
98+ loadStateMock . mockReturnValue ( { files_list_filter_status : '' , files_list_filter_modified : 'last-7' } )
99+
100+ const { useFiltersStore : freshStore } = await import ( '../../store/filters.js' )
101+ const store = freshStore ( )
102+
103+ expect ( store . filter_modified ) . toBe ( 'last-7' )
104+ } )
105+
106+ it ( 'defaults to empty string when keys are absent' , async ( ) => {
107+ const loadStateMock = loadState as MockedFunction < typeof loadState >
108+ loadStateMock . mockReturnValue ( { } )
109+
110+ const { useFiltersStore : freshStore } = await import ( '../../store/filters.js' )
111+ const store = freshStore ( )
112+
113+ expect ( store . filter_status ) . toBe ( '' )
114+ expect ( store . filter_modified ) . toBe ( '' )
115+ } )
116+ } )
117+
81118 describe ( 'business rule: activeChips should return all active chips from all filters' , ( ) => {
82119 it ( 'returns empty array when there are no chips' , ( ) => {
83120 const store = useFiltersStore ( )
@@ -157,8 +194,49 @@ describe('filters store - filter business rules', () => {
157194 } )
158195 } )
159196
160- describe ( 'business rule: chips update should emit filter event' , ( ) => {
161- it ( 'onFilterUpdateChips should emit libresign:filters:update event' , async ( ) => {
197+ describe ( 'business rule: filterModifiedRange should compute date range from preset id' , ( ) => {
198+ it ( 'returns null when filter_modified is empty' , ( ) => {
199+ const store = useFiltersStore ( )
200+ store . filter_modified = ''
201+
202+ expect ( store . filterModifiedRange ) . toBeNull ( )
203+ } )
204+
205+ it ( 'returns null for unknown preset id' , ( ) => {
206+ const store = useFiltersStore ( )
207+ store . filter_modified = 'unknown-preset'
208+
209+ expect ( store . filterModifiedRange ) . toBeNull ( )
210+ } )
211+
212+ it . each ( [ 'today' , 'last-7' , 'last-30' , 'this-year' , 'last-year' ] ) ( 'returns { start, end } for preset "%s"' , ( presetId ) => {
213+ const store = useFiltersStore ( )
214+ store . filter_modified = presetId
215+
216+ const range = store . filterModifiedRange
217+ expect ( range ) . not . toBeNull ( )
218+ expect ( range ?. start ) . toBeTypeOf ( 'number' )
219+ expect ( range ?. end ) . toBeTypeOf ( 'number' )
220+ expect ( range ! . start ) . toBeLessThan ( range ! . end )
221+ } )
222+
223+ it ( 'today preset: start is midnight and end is end of day' , ( ) => {
224+ const store = useFiltersStore ( )
225+ store . filter_modified = 'today'
226+
227+ const range = store . filterModifiedRange !
228+ const startDate = new Date ( range . start )
229+ const endDate = new Date ( range . end )
230+
231+ expect ( startDate . getHours ( ) ) . toBe ( 0 )
232+ expect ( startDate . getMinutes ( ) ) . toBe ( 0 )
233+ expect ( endDate . getHours ( ) ) . toBe ( 23 )
234+ expect ( endDate . getMinutes ( ) ) . toBe ( 59 )
235+ } )
236+ } )
237+
238+ describe ( 'business rule: chips update should only update UI chips state' , ( ) => {
239+ it ( 'onFilterUpdateChips should NOT emit libresign:filters:update event' , async ( ) => {
162240 const store = useFiltersStore ( )
163241 const event = {
164242 id : 'status' ,
@@ -167,7 +245,7 @@ describe('filters store - filter business rules', () => {
167245
168246 await store . onFilterUpdateChips ( event )
169247
170- expect ( emit ) . toHaveBeenCalledWith ( 'libresign:filters:update' )
248+ expect ( emit ) . not . toHaveBeenCalled ( )
171249 } )
172250
173251 it ( 'onFilterUpdateChips should update chips for specific filter' , async ( ) => {
@@ -213,7 +291,7 @@ describe('filters store - filter business rules', () => {
213291 await store . onFilterUpdateChipsAndSave ( event )
214292
215293 expect ( axiosMock . put ) . toHaveBeenCalledWith (
216- '/ocs/v2.php/apps/libresign/api/v1/account/config/filter_modified ' ,
294+ '/ocs/v2.php/apps/libresign/api/v1/account/config/files_list_filter_modified ' ,
217295 { value : 'today' }
218296 )
219297 } )
@@ -233,7 +311,7 @@ describe('filters store - filter business rules', () => {
233311 await store . onFilterUpdateChipsAndSave ( event )
234312
235313 expect ( axiosMock . put ) . toHaveBeenCalledWith (
236- '/ocs/v2.php/apps/libresign/api/v1/account/config/filter_modified ' ,
314+ '/ocs/v2.php/apps/libresign/api/v1/account/config/files_list_filter_modified ' ,
237315 { value : 'today' }
238316 )
239317 } )
@@ -250,10 +328,39 @@ describe('filters store - filter business rules', () => {
250328 await store . onFilterUpdateChipsAndSave ( event )
251329
252330 expect ( axiosMock . put ) . toHaveBeenCalledWith (
253- '/ocs/v2.php/apps/libresign/api/v1/account/config/filter_modified ' ,
331+ '/ocs/v2.php/apps/libresign/api/v1/account/config/files_list_filter_modified ' ,
254332 { value : '' }
255333 )
256334 } )
335+
336+ it ( 'modified filter should update local state after saving' , async ( ) => {
337+ axiosMock . put . mockResolvedValue ( { data : { success : true } } )
338+
339+ const store = useFiltersStore ( )
340+ const event = {
341+ id : 'modified' ,
342+ detail : [ { id : 'today' , label : 'Today' } ] ,
343+ }
344+
345+ await store . onFilterUpdateChipsAndSave ( event )
346+
347+ expect ( store . filter_modified ) . toBe ( 'today' )
348+ } )
349+
350+ it ( 'empty modified filter should clear local state' , async ( ) => {
351+ axiosMock . put . mockResolvedValue ( { data : { success : true } } )
352+
353+ const store = useFiltersStore ( )
354+ store . filter_modified = 'last-7'
355+ const event = {
356+ id : 'modified' ,
357+ detail : [ ] ,
358+ }
359+
360+ await store . onFilterUpdateChipsAndSave ( event )
361+
362+ expect ( store . filter_modified ) . toBe ( '' )
363+ } )
257364 } )
258365
259366 describe ( 'business rule: status filter should save JSON array to server' , ( ) => {
@@ -272,7 +379,7 @@ describe('filters store - filter business rules', () => {
272379 await store . onFilterUpdateChipsAndSave ( event )
273380
274381 expect ( axiosMock . put ) . toHaveBeenCalledWith (
275- '/ocs/v2.php/apps/libresign/api/v1/account/config/filter_status ' ,
382+ '/ocs/v2.php/apps/libresign/api/v1/account/config/files_list_filter_status ' ,
276383 { value : '["signed","pending"]' }
277384 )
278385 } )
@@ -289,7 +396,7 @@ describe('filters store - filter business rules', () => {
289396 await store . onFilterUpdateChipsAndSave ( event )
290397
291398 expect ( axiosMock . put ) . toHaveBeenCalledWith (
292- '/ocs/v2.php/apps/libresign/api/v1/account/config/filter_status ' ,
399+ '/ocs/v2.php/apps/libresign/api/v1/account/config/files_list_filter_status ' ,
293400 { value : '' }
294401 )
295402 } )
0 commit comments